0.3.00
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
// MetadataHeroSettingsKey is the app_settings row backing the household-wide metadata
|
||||
// hero composition.
|
||||
const MetadataHeroSettingsKey = "metadata_hero_settings"
|
||||
|
||||
const (
|
||||
MetadataHeroTitle = "title"
|
||||
MetadataHeroRatings = "ratings"
|
||||
MetadataHeroFacts = "facts"
|
||||
MetadataHeroSummary = "summary"
|
||||
MetadataHeroReason = "recommendation_reason"
|
||||
MetadataHeroTime = "time_remaining"
|
||||
)
|
||||
|
||||
var DefaultMetadataHeroContentOrder = []string{
|
||||
MetadataHeroTitle,
|
||||
MetadataHeroRatings,
|
||||
MetadataHeroFacts,
|
||||
MetadataHeroSummary,
|
||||
}
|
||||
|
||||
var MetadataHeroContentOptions = []string{
|
||||
MetadataHeroTitle,
|
||||
MetadataHeroRatings,
|
||||
MetadataHeroFacts,
|
||||
MetadataHeroSummary,
|
||||
MetadataHeroReason,
|
||||
MetadataHeroTime,
|
||||
}
|
||||
|
||||
// MetadataHeroSettings is one presentation decision for the whole household. It lives
|
||||
// outside user preferences because the hero is part of the product's shared composition,
|
||||
// not something that should change when the viewer changes.
|
||||
type MetadataHeroSettings struct {
|
||||
ContentOrder []string `json:"contentOrder"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
UpdatedBy string `json:"updatedBy,omitempty"`
|
||||
}
|
||||
|
||||
func NormalizeMetadataHeroSettings(settings MetadataHeroSettings) MetadataHeroSettings {
|
||||
seen := map[string]bool{}
|
||||
order := make([]string, 0, len(MetadataHeroContentOptions))
|
||||
for _, entry := range settings.ContentOrder {
|
||||
if seen[entry] || !containsString(MetadataHeroContentOptions, entry) {
|
||||
continue
|
||||
}
|
||||
seen[entry] = true
|
||||
order = append(order, entry)
|
||||
}
|
||||
if len(order) == 0 {
|
||||
order = append([]string(nil), DefaultMetadataHeroContentOrder...)
|
||||
}
|
||||
settings.ContentOrder = order
|
||||
return settings
|
||||
}
|
||||
|
||||
func (s *Store) MetadataHeroSettings(ctx context.Context) (MetadataHeroSettings, error) {
|
||||
var raw []byte
|
||||
err := s.pool.QueryRow(ctx,
|
||||
`SELECT value FROM app_settings WHERE key = $1`, MetadataHeroSettingsKey).Scan(&raw)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return NormalizeMetadataHeroSettings(MetadataHeroSettings{}), nil
|
||||
}
|
||||
if err != nil {
|
||||
return MetadataHeroSettings{}, fmt.Errorf("store: read metadata hero settings: %w", err)
|
||||
}
|
||||
var settings MetadataHeroSettings
|
||||
if err := json.Unmarshal(raw, &settings); err != nil {
|
||||
return MetadataHeroSettings{}, fmt.Errorf("store: decode metadata hero settings: %w", err)
|
||||
}
|
||||
return NormalizeMetadataHeroSettings(settings), nil
|
||||
}
|
||||
|
||||
func (s *Store) SetMetadataHeroSettings(
|
||||
ctx context.Context, settings MetadataHeroSettings,
|
||||
) (MetadataHeroSettings, error) {
|
||||
settings = NormalizeMetadataHeroSettings(settings)
|
||||
settings.UpdatedAt = time.Now().UTC()
|
||||
raw, err := json.Marshal(settings)
|
||||
if err != nil {
|
||||
return MetadataHeroSettings{}, err
|
||||
}
|
||||
_, err = s.pool.Exec(ctx, `
|
||||
INSERT INTO app_settings (key, value, updated_at)
|
||||
VALUES ($1, $2::jsonb, now())
|
||||
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = now()`,
|
||||
MetadataHeroSettingsKey, string(raw))
|
||||
if err != nil {
|
||||
return MetadataHeroSettings{}, fmt.Errorf("store: write metadata hero settings: %w", err)
|
||||
}
|
||||
return settings, nil
|
||||
}
|
||||
Reference in New Issue
Block a user