75 lines
2.5 KiB
Go
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)
|