2026-07-23 20:58:48 +08:00

75 lines
2.5 KiB
Go

package appconfig
import (
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
"strings"
)
const (
giftConfigGroup = "room-gift"
giftQuantityPresetsKey = "quantity-presets"
giftQuantityPresetMaxCount = 8
giftQuantityPresetMaxValue = 9_999
)
const getGiftQuantityPresetsSQL = `
SELECT COALESCE(value, '')
FROM admin_app_configs
WHERE app_code = ? AND ` + "`group`" + ` = ? AND ` + "`key`" + ` = ? AND is_deleted = FALSE
LIMIT 1`
// DefaultGiftQuantityPresets preserves the existing product behavior for Apps that have not saved
// their own room-gift configuration. Callers receive a copy so request-local fallback cannot mutate it.
func DefaultGiftQuantityPresets() []int32 {
return []int32{1, 9, 99, 999}
}
// GiftQuantityPresets resolves only the selected App's row. The three-column unique index makes this
// a bounded point lookup; a missing row is a normal compatibility fallback, not a cross-App baseline.
func (r *MySQLReader) GiftQuantityPresets(ctx context.Context, appCode string) ([]int32, error) {
if r == nil || r.db == nil {
return nil, errors.New("app config reader is not configured")
}
appCode = normalizeAppCode(appCode)
var raw string
err := r.db.QueryRowContext(ctx, getGiftQuantityPresetsSQL, appCode, giftConfigGroup, giftQuantityPresetsKey).Scan(&raw)
if errors.Is(err, sql.ErrNoRows) {
return DefaultGiftQuantityPresets(), nil
}
if err != nil {
return nil, err
}
var presets []int32
if err := json.Unmarshal([]byte(strings.TrimSpace(raw)), &presets); err != nil {
return nil, fmt.Errorf("parse gift quantity presets for app %s: %w", appCode, err)
}
return normalizeGiftQuantityPresets(presets)
}
func normalizeGiftQuantityPresets(values []int32) ([]int32, error) {
if len(values) == 0 || len(values) > giftQuantityPresetMaxCount {
return nil, fmt.Errorf("gift quantity presets must contain between 1 and %d values", giftQuantityPresetMaxCount)
}
normalized := make([]int32, len(values))
var previous int32
for index, value := range values {
if value < 1 || value > giftQuantityPresetMaxValue {
return nil, fmt.Errorf("gift quantity preset must be between 1 and %d", giftQuantityPresetMaxValue)
}
if index > 0 && value <= previous {
return nil, errors.New("gift quantity presets must be strictly increasing and unique")
}
normalized[index] = value
previous = value
}
return normalized, nil
}
var _ interface {
GiftQuantityPresets(context.Context, string) ([]int32, error)
} = (*MySQLReader)(nil)