package cache import ( "context" "fmt" "time" "img_infinite_canvas/internal/domain/design" ) const projectListKeyPrefix = "design:projects:list" type ProjectRepository struct { next design.Repository store Store ttl time.Duration } func NewProjectRepository(next design.Repository, store Store, ttl time.Duration) *ProjectRepository { return &ProjectRepository{ next: next, store: store, ttl: ttl, } } func (r *ProjectRepository) List(ctx context.Context) ([]design.ProjectSummary, error) { var projects []design.ProjectSummary ok, err := r.store.Get(ctx, projectListKey(ctx), &projects) if err == nil && ok { return projects, nil } projects, err = r.next.List(ctx) if err != nil { return nil, err } _ = r.store.Set(ctx, projectListKey(ctx), projects, r.ttl) return projects, nil } func (r *ProjectRepository) ListPage(ctx context.Context, limit int64, offset int64) ([]design.ProjectSummary, error) { return r.next.ListPage(ctx, limit, offset) } func (r *ProjectRepository) Get(ctx context.Context, id string) (design.Project, error) { var project design.Project ok, err := r.store.Get(ctx, projectKey(ctx, id), &project) if err == nil && ok { return project, nil } project, err = r.next.Get(ctx, id) if err != nil { return design.Project{}, err } _ = r.store.Set(ctx, projectKey(ctx, id), project, r.ttl) return project, nil } func (r *ProjectRepository) Save(ctx context.Context, project design.Project) error { if err := r.next.Save(ctx, project); err != nil { return err } _ = r.store.Set(ctx, projectKey(ctx, project.ID), project, r.ttl) _ = r.store.Delete(ctx, projectListKey(ctx)) return nil } func (r *ProjectRepository) SaveCanvas(ctx context.Context, project design.Project, baseVersion string) error { next, ok := r.next.(design.CanvasRepository) if !ok { return r.Save(ctx, project) } if err := next.SaveCanvas(ctx, project, baseVersion); err != nil { return err } _ = r.store.Delete(ctx, projectKey(ctx, project.ID)) _ = r.store.Delete(ctx, projectListKey(ctx)) return nil } func (r *ProjectRepository) Delete(ctx context.Context, id string) error { if err := r.next.Delete(ctx, id); err != nil { return err } _ = r.store.Delete(ctx, projectKey(ctx, id)) _ = r.store.Delete(ctx, projectListKey(ctx)) return nil } func (r *ProjectRepository) SaveMockupBlob(ctx context.Context, blob design.MockupBlobData) error { next, ok := r.next.(design.MockupBlobRepository) if !ok { return nil } return next.SaveMockupBlob(ctx, blob) } func (r *ProjectRepository) GetMockupBlob(ctx context.Context, dataID string) (design.MockupBlobData, error) { next, ok := r.next.(design.MockupBlobRepository) if !ok { return design.MockupBlobData{}, design.ErrNotFound } return next.GetMockupBlob(ctx, dataID) } func projectListKey(ctx context.Context) string { return fmt.Sprintf("%s:%s", projectListKeyPrefix, design.UserIDFromContext(ctx)) } func projectKey(ctx context.Context, id string) string { return fmt.Sprintf("design:projects:%s:%s", design.UserIDFromContext(ctx), id) }