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