1package bug
2
3import (
4 "encoding/json"
5
6 "github.com/pkg/errors"
7
8 "github.com/MichaelMure/git-bug/entity"
9 "github.com/MichaelMure/git-bug/identity"
10)
11
12var _ Operation = &SetMetadataOperation{}
13
14type SetMetadataOperation struct {
15 OpBase
16 Target entity.Id `json:"target"`
17 NewMetadata map[string]string `json:"new_metadata"`
18}
19
20// Sign-post method for gqlgen
21func (op *SetMetadataOperation) IsOperation() {}
22
23func (op *SetMetadataOperation) base() *OpBase {
24 return &op.OpBase
25}
26
27func (op *SetMetadataOperation) Id() entity.Id {
28 return idOperation(op)
29}
30
31func (op *SetMetadataOperation) Apply(snapshot *Snapshot) {
32 for _, target := range snapshot.Operations {
33 if target.Id() == op.Target {
34 base := target.base()
35
36 if base.extraMetadata == nil {
37 base.extraMetadata = make(map[string]string)
38 }
39
40 // Apply the metadata in an immutable way: if a metadata already
41 // exist, it's not possible to override it.
42 for key, val := range op.NewMetadata {
43 if _, exist := base.extraMetadata[key]; !exist {
44 base.extraMetadata[key] = val
45 }
46 }
47
48 return
49 }
50 }
51}
52
53func (op *SetMetadataOperation) Validate() error {
54 if err := opBaseValidate(op, SetMetadataOp); err != nil {
55 return err
56 }
57
58 if err := op.Target.Validate(); err != nil {
59 return errors.Wrap(err, "target invalid")
60 }
61
62 return nil
63}
64
65// UnmarshalJSON is a two step JSON unmarshaling
66// This workaround is necessary to avoid the inner OpBase.MarshalJSON
67// overriding the outer op's MarshalJSON
68func (op *SetMetadataOperation) UnmarshalJSON(data []byte) error {
69 // Unmarshal OpBase and the op separately
70
71 base := OpBase{}
72 err := json.Unmarshal(data, &base)
73 if err != nil {
74 return err
75 }
76
77 aux := struct {
78 Target entity.Id `json:"target"`
79 NewMetadata map[string]string `json:"new_metadata"`
80 }{}
81
82 err = json.Unmarshal(data, &aux)
83 if err != nil {
84 return err
85 }
86
87 op.OpBase = base
88 op.Target = aux.Target
89 op.NewMetadata = aux.NewMetadata
90
91 return nil
92}
93
94// Sign post method for gqlgen
95func (op *SetMetadataOperation) IsAuthored() {}
96
97func NewSetMetadataOp(author identity.Interface, unixTime int64, target entity.Id, newMetadata map[string]string) *SetMetadataOperation {
98 return &SetMetadataOperation{
99 OpBase: newOpBase(SetMetadataOp, author, unixTime),
100 Target: target,
101 NewMetadata: newMetadata,
102 }
103}
104
105// Convenience function to apply the operation
106func SetMetadata(b Interface, author identity.Interface, unixTime int64, target entity.Id, newMetadata map[string]string) (*SetMetadataOperation, error) {
107 SetMetadataOp := NewSetMetadataOp(author, unixTime, target, newMetadata)
108 if err := SetMetadataOp.Validate(); err != nil {
109 return nil, err
110 }
111 b.Append(SetMetadataOp)
112 return SetMetadataOp, nil
113}