package entry import ( "RenewCMS/internal/domain/contenttype" "fmt" "reflect" "sort" "strconv" "strings" ) func SameValue(left any, right any) bool { return reflect.DeepEqual(left, right) } type UniqueValue struct { Key string Value any } func ApplyDefaults(fields []contenttype.Field, data map[string]any) map[string]any { filled := make(map[string]any, len(data)) for key, value := range data { filled[key] = value } for _, field := range fields { if _, present := filled[field.Key]; !present && field.Default != nil { filled[field.Key] = field.Default } } return filled } func Project(fields []contenttype.Field, data map[string]any) map[string]any { projected := make(map[string]any, len(data)) for _, field := range fields { if value, present := data[field.Key]; present { projected[field.Key] = value } } return projected } func Validate(fields []contenttype.Field, data map[string]any) error { for _, field := range fields { if err := validateField(field, data); err != nil { return err } } return firstUnknownField(fields, data) } func validateField(field contenttype.Field, data map[string]any) error { value := data[field.Key] if value == nil || contenttype.EmptyRelation(field, value) { if field.Required { return InvalidField(field.Key, RuleRequired) } return nil } if rule := field.Violation(value); rule != "" { return InvalidField(field.Key, rule) } return nil } func firstUnknownField(fields []contenttype.Field, data map[string]any) error { known := make(map[string]bool, len(fields)) for _, field := range fields { known[field.Key] = true } var unknown []string for key := range data { if !known[key] { unknown = append(unknown, key) } } if len(unknown) == 0 { return nil } sort.Strings(unknown) return InvalidField(unknown[0], RuleUnknownField) } func UniqueValues(fields []contenttype.Field, data map[string]any) []UniqueValue { var values []UniqueValue for _, field := range fields { if value := data[field.Key]; (field.Unique || field.IsExclusiveRelation()) && value != nil { values = append(values, UniqueValue{Key: field.Key, Value: value}) } } return values } func MediaIDs(fields []contenttype.Field, data map[string]any) map[string]uint32 { ids := map[string]uint32{} for _, ref := range contenttype.MediaRefs(fields, data) { ids[ref.Field.Key] = ref.ID } return ids } func MissingMedia(field contenttype.Field, unchanged bool) error { if unchanged { return InvalidField(field.Key, RuleRequired) } return InvalidField(field.Key, contenttype.RuleType) } func RelationIDs(fields []contenttype.Field, data map[string]any) map[string]map[uint32]bool { ids := map[string]map[uint32]bool{} for _, ref := range contenttype.RelationRefs(fields, data) { held := make(map[uint32]bool, len(ref.IDs)) for _, id := range ref.IDs { held[id] = true } ids[ref.Field.Key] = held } return ids } func MissingRelation(field contenttype.Field, unchanged bool) error { return MissingMedia(field, unchanged) } func MatchesQuery(fields []contenttype.Field, data map[string]any, query string) bool { if len(fields) == 0 { return false } return strings.Contains(strings.ToLower(displayText(data[fields[0].Key])), strings.ToLower(query)) } func displayText(value any) string { switch typed := value.(type) { case nil: return "" case string: return typed case float64: return strconv.FormatFloat(typed, 'f', -1, 64) } return fmt.Sprint(value) }