op_set_metadata.go

 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
20func (op *SetMetadataOperation) Id() entity.Id {
21	return idOperation(op, &op.OpBase)
22}
23
24func (op *SetMetadataOperation) Apply(snapshot *Snapshot) {
25	for _, target := range snapshot.Operations {
26		if target.Id() == op.Target {
27			// Apply the metadata in an immutable way: if a metadata already
28			// exist, it's not possible to override it.
29			for key, value := range op.NewMetadata {
30				target.setExtraMetadataImmutable(key, value)
31			}
32			return
33		}
34	}
35}
36
37func (op *SetMetadataOperation) Validate() error {
38	if err := op.OpBase.Validate(op, SetMetadataOp); err != nil {
39		return err
40	}
41
42	if err := op.Target.Validate(); err != nil {
43		return errors.Wrap(err, "target invalid")
44	}
45
46	return nil
47}
48
49// UnmarshalJSON is a two step JSON unmarshalling
50// This workaround is necessary to avoid the inner OpBase.MarshalJSON
51// overriding the outer op's MarshalJSON
52func (op *SetMetadataOperation) UnmarshalJSON(data []byte) error {
53	// Unmarshal OpBase and the op separately
54
55	base := OpBase{}
56	err := json.Unmarshal(data, &base)
57	if err != nil {
58		return err
59	}
60
61	aux := struct {
62		Target      entity.Id         `json:"target"`
63		NewMetadata map[string]string `json:"new_metadata"`
64	}{}
65
66	err = json.Unmarshal(data, &aux)
67	if err != nil {
68		return err
69	}
70
71	op.OpBase = base
72	op.Target = aux.Target
73	op.NewMetadata = aux.NewMetadata
74
75	return nil
76}
77
78// Sign post method for gqlgen
79func (op *SetMetadataOperation) IsAuthored() {}
80
81func NewSetMetadataOp(author identity.Interface, unixTime int64, target entity.Id, newMetadata map[string]string) *SetMetadataOperation {
82	return &SetMetadataOperation{
83		OpBase:      newOpBase(SetMetadataOp, author, unixTime),
84		Target:      target,
85		NewMetadata: newMetadata,
86	}
87}
88
89// Convenience function to apply the operation
90func SetMetadata(b Interface, author identity.Interface, unixTime int64, target entity.Id, newMetadata map[string]string) (*SetMetadataOperation, error) {
91	SetMetadataOp := NewSetMetadataOp(author, unixTime, target, newMetadata)
92	if err := SetMetadataOp.Validate(); err != nil {
93		return nil, err
94	}
95	b.Append(SetMetadataOp)
96	return SetMetadataOp, nil
97}