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}