Skip to content

Commit b6aeaa7

Browse files
committed
feature: serialize JSON LabelSet as array of strings
This commit improves the JSON serialization of the LabelSet struct by changing the way labels are represented in JSON. Instead of using a map with string keys and string values, the labels are now represented as an array of strings. This change simplifies the JSON structure and makes it easier to work with labels in a more intuitive way.
1 parent c365d97 commit b6aeaa7

File tree

4 files changed

+323
-158
lines changed

4 files changed

+323
-158
lines changed

.changeset/three-melons-stand.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"chainlink-deployments-framework": patch
3+
---
4+
5+
Datastore labels are now serialized into JSON as an array of strings

datastore/address_ref.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package datastore
22

33
import (
44
"errors"
5-
"maps"
65

76
"github.com/Masterminds/semver/v3"
87
)
@@ -51,7 +50,7 @@ func (r AddressRef) Clone() AddressRef {
5150
Version: r.Version,
5251
Qualifier: r.Qualifier,
5352
Address: r.Address,
54-
Labels: maps.Clone(r.Labels),
53+
Labels: r.Labels.Clone(),
5554
}
5655
}
5756

datastore/label_set.go

+64-34
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,51 @@
11
package datastore
22

33
import (
4-
"sort"
4+
"encoding/json"
5+
"maps"
6+
"slices"
57
"strings"
68
)
79

810
// LabelSet represents a set of labels on an address book entry.
9-
type LabelSet map[string]struct{}
11+
type LabelSet struct {
12+
elements map[string]struct{}
13+
}
1014

1115
// NewLabelSet initializes a new LabelSet with any number of labels.
1216
func NewLabelSet(labels ...string) LabelSet {
13-
set := make(LabelSet)
14-
for _, lb := range labels {
15-
set[lb] = struct{}{}
17+
set := make(map[string]struct{}, len(labels))
18+
for _, l := range labels {
19+
set[l] = struct{}{}
1620
}
1721

18-
return set
22+
return LabelSet{
23+
elements: set,
24+
}
1925
}
2026

2127
// Add inserts a label into the set.
22-
func (ls LabelSet) Add(label string) {
23-
ls[label] = struct{}{}
28+
func (s LabelSet) Add(label string) {
29+
s.elements[label] = struct{}{}
2430
}
2531

2632
// Remove deletes a label from the set, if it exists.
27-
func (ls LabelSet) Remove(label string) {
28-
delete(ls, label)
33+
func (s LabelSet) Remove(label string) {
34+
delete(s.elements, label)
2935
}
3036

3137
// Contains checks if the set contains the given label.
32-
func (ls LabelSet) Contains(label string) bool {
33-
_, ok := ls[label]
38+
func (s LabelSet) Contains(label string) bool {
39+
_, ok := s.elements[label]
40+
3441
return ok
3542
}
3643

3744
// String returns the labels as a sorted, space-separated string.
38-
// It implements the fmt.Stringer interface.
39-
func (ls LabelSet) String() string {
40-
labels := ls.List()
45+
//
46+
// Implements the fmt.Stringer interface.
47+
func (s LabelSet) String() string {
48+
labels := s.List()
4149
if len(labels) == 0 {
4250
return ""
4351
}
@@ -47,38 +55,60 @@ func (ls LabelSet) String() string {
4755
}
4856

4957
// List returns the labels as a sorted slice of strings.
50-
func (ls LabelSet) List() []string {
51-
if len(ls) == 0 {
58+
func (s LabelSet) List() []string {
59+
if len(s.elements) == 0 {
5260
return []string{}
5361
}
5462

5563
// Collect labels into a slice
56-
labels := make([]string, 0, len(ls))
57-
for label := range ls {
58-
labels = append(labels, label)
59-
}
64+
labels := slices.Collect(maps.Keys(s.elements))
6065

6166
// Sort the labels to ensure consistent ordering
62-
sort.Strings(labels)
67+
slices.Sort(labels)
6368

6469
return labels
6570
}
6671

6772
// Equal checks if two LabelSets are equal.
68-
func (ls LabelSet) Equal(other LabelSet) bool {
69-
if len(ls) != len(other) {
70-
return false
71-
}
72-
for label := range ls {
73-
if _, ok := other[label]; !ok {
74-
return false
75-
}
76-
}
73+
func (s LabelSet) Equal(other LabelSet) bool {
74+
return maps.Equal(s.elements, other.elements)
75+
}
7776

78-
return true
77+
// Len returns the number of labels in the set.
78+
func (s LabelSet) Length() int {
79+
return len(s.elements)
7980
}
8081

8182
// IsEmpty checks if the LabelSet is empty.
82-
func (ls LabelSet) IsEmpty() bool {
83-
return len(ls) == 0
83+
func (s LabelSet) IsEmpty() bool {
84+
return s.Length() == 0
85+
}
86+
87+
// Clone creates a copy of the LabelSet.
88+
func (s LabelSet) Clone() LabelSet {
89+
return LabelSet{
90+
elements: maps.Clone(s.elements),
91+
}
92+
}
93+
94+
// MarshalJSON marshals the LabelSet as a JSON array of strings.
95+
//
96+
// Implements the json.Marshaler interface.
97+
func (s LabelSet) MarshalJSON() ([]byte, error) {
98+
return json.Marshal(s.List())
99+
}
100+
101+
// UnmarshalJSON unmarshals a JSON array of strings into the LabelSet.
102+
//
103+
// Implements the json.Unmarshaler interface.
104+
func (s *LabelSet) UnmarshalJSON(data []byte) error {
105+
var labels []string
106+
if err := json.Unmarshal(data, &labels); err != nil {
107+
return err
108+
}
109+
110+
// Initialize the LabelSet with the unmarshaled labels
111+
*s = NewLabelSet(labels...)
112+
113+
return nil
84114
}

0 commit comments

Comments
 (0)