rule.go

 1// Copyright 2020 Jebbs. All rights reserved.
 2// Use of this source code is governed by MIT
 3// license that can be found in the LICENSE file.
 4
 5package rule
 6
 7// Rule is the merge rules
 8type Rule struct {
 9	OrderBy []Field
10	MergeBy []Field
11}
12
13// NewRule makes a new Rule
14func NewRule(fields ...Field) *Rule {
15	r := &Rule{}
16	for _, field := range fields {
17		switch field.Type {
18		case FieldTypeMerge:
19			r.MergeBy = append(r.MergeBy, field)
20		case FieldTypeOrder:
21			r.OrderBy = append(r.OrderBy, field)
22		}
23	}
24	return r
25}
26
27// Apply applies rule according to m
28func (r *Rule) Apply(m map[string]interface{}) error {
29	if r == nil || (len(r.MergeBy) == 0 && len(r.OrderBy) == 0) {
30		return nil
31	}
32	err := r.sortMergeSlices(m)
33	if err != nil {
34		return err
35	}
36	r.removeHelperFields(m)
37	return nil
38}
39
40// sortMergeSlices enumerates all slices in a map, to sort by order and merge by tag
41func (r *Rule) sortMergeSlices(target map[string]interface{}) error {
42	for key, value := range target {
43		if slice, ok := value.([]interface{}); ok {
44			sortByFields(slice, r.OrderBy)
45			s, err := mergeByFields(slice, r.MergeBy)
46			if err != nil {
47				return err
48			}
49			target[key] = s
50			for _, item := range s {
51				if m, ok := item.(map[string]interface{}); ok {
52					r.sortMergeSlices(m)
53				}
54			}
55		} else if field, ok := value.(map[string]interface{}); ok {
56			r.sortMergeSlices(field)
57		}
58	}
59	return nil
60}
61
62func (r *Rule) removeHelperFields(target map[string]interface{}) {
63	for key, value := range target {
64		if r.shouldDelete(key) {
65			delete(target, key)
66		} else if slice, ok := value.([]interface{}); ok {
67			for _, e := range slice {
68				if el, ok := e.(map[string]interface{}); ok {
69					r.removeHelperFields(el)
70				}
71			}
72		} else if field, ok := value.(map[string]interface{}); ok {
73			r.removeHelperFields(field)
74		}
75	}
76}
77
78// shouldDelete tells if the field should be deleted according to the rules
79func (r *Rule) shouldDelete(key string) bool {
80	for _, field := range r.MergeBy {
81		if key != field.Key {
82			continue
83		}
84		return field.Remove
85	}
86	for _, field := range r.OrderBy {
87		if key != field.Key {
88			continue
89		}
90		return field.Remove
91	}
92	return false
93}