op_set_metadata.go

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