op_set_metadata.go

  1package bug
  2
  3import (
  4	"encoding/json"
  5
  6	"github.com/MichaelMure/git-bug/identity"
  7	"github.com/MichaelMure/git-bug/util/git"
  8)
  9
 10var _ Operation = &SetMetadataOperation{}
 11
 12type SetMetadataOperation struct {
 13	OpBase
 14	Target      git.Hash
 15	NewMetadata map[string]string
 16}
 17
 18func (op *SetMetadataOperation) base() *OpBase {
 19	return &op.OpBase
 20}
 21
 22func (op *SetMetadataOperation) Hash() (git.Hash, error) {
 23	return hashOperation(op)
 24}
 25
 26func (op *SetMetadataOperation) Apply(snapshot *Snapshot) {
 27	for _, target := range snapshot.Operations {
 28		hash, err := target.Hash()
 29		if err != nil {
 30			// Should never error unless a programming error happened
 31			// (covered in OpBase.Validate())
 32			panic(err)
 33		}
 34
 35		if hash == op.Target {
 36			base := target.base()
 37
 38			if base.extraMetadata == nil {
 39				base.extraMetadata = make(map[string]string)
 40			}
 41
 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	return nil
 59}
 60
 61// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op
 62// MarshalJSON
 63func (op *SetMetadataOperation) MarshalJSON() ([]byte, error) {
 64	base, err := json.Marshal(op.OpBase)
 65	if err != nil {
 66		return nil, err
 67	}
 68
 69	// revert back to a flat map to be able to add our own fields
 70	var data map[string]interface{}
 71	if err := json.Unmarshal(base, &data); err != nil {
 72		return nil, err
 73	}
 74
 75	data["target"] = op.Target
 76	data["new_metadata"] = op.NewMetadata
 77
 78	return json.Marshal(data)
 79}
 80
 81// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op
 82// MarshalJSON
 83func (op *SetMetadataOperation) UnmarshalJSON(data []byte) error {
 84	// Unmarshal OpBase and the op separately
 85
 86	base := OpBase{}
 87	err := json.Unmarshal(data, &base)
 88	if err != nil {
 89		return err
 90	}
 91
 92	aux := struct {
 93		Target      git.Hash          `json:"target"`
 94		NewMetadata map[string]string `json:"new_metadata"`
 95	}{}
 96
 97	err = json.Unmarshal(data, &aux)
 98	if err != nil {
 99		return err
100	}
101
102	op.OpBase = base
103	op.Target = aux.Target
104	op.NewMetadata = aux.NewMetadata
105
106	return nil
107}
108
109// Sign post method for gqlgen
110func (op *SetMetadataOperation) IsAuthored() {}
111
112func NewSetMetadataOp(author identity.Interface, unixTime int64, target git.Hash, newMetadata map[string]string) *SetMetadataOperation {
113	return &SetMetadataOperation{
114		OpBase:      newOpBase(SetMetadataOp, author, unixTime),
115		Target:      target,
116		NewMetadata: newMetadata,
117	}
118}
119
120// Convenience function to apply the operation
121func SetMetadata(b Interface, author identity.Interface, unixTime int64, target git.Hash, newMetadata map[string]string) (*SetMetadataOperation, error) {
122	SetMetadataOp := NewSetMetadataOp(author, unixTime, target, newMetadata)
123	if err := SetMetadataOp.Validate(); err != nil {
124		return nil, err
125	}
126	b.Append(SetMetadataOp)
127	return SetMetadataOp, nil
128}