aboutsummaryrefslogtreecommitdiffstats
path: root/bug/bug.go
blob: b36246e3b3c320ae5952168158eea7e7f163ddde (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package bug

import (
	"github.com/kevinburke/go.uuid"
)

// Bug hold the data of a bug thread, organized in a way close to
// how it will be persisted inside Git. This is the datastructure
// used for merge of two different version.
type Bug struct {
	// Id used as unique identifier
	Id uuid.UUID

	// TODO: need a way to order bugs
	// Probably a Lamport clock

	Packs []OperationPack

	Staging OperationPack
}

// Create a new Bug
func NewBug() (*Bug, error) {

	// Creating UUID Version 4
	id, err := uuid.ID4()

	if err != nil {
		return nil, err
	}

	return &Bug{
		Id: id,
	}, nil
}

// IsValid check if the Bug data is valid
func (bug *Bug) IsValid() bool {
	// non-empty
	if len(bug.Packs) == 0 && bug.Staging.IsEmpty() {
		return false
	}

	// check if each pack is valid
	for _, pack := range bug.Packs {
		if !pack.IsValid() {
			return false
		}
	}

	// check if Staging is valid if needed
	if !bug.Staging.IsEmpty() {
		if !bug.Staging.IsValid() {
			return false
		}
	}

	// The very first Op should be a CREATE
	firstOp := bug.firstOp()
	if firstOp == nil || firstOp.OpType() != CREATE {
		return false
	}

	// Check that there is no more CREATE op
	it := NewOperationIterator(bug)
	createCount := 0
	for it.Next() {
		if it.Value().OpType() == CREATE {
			createCount++
		}
	}

	if createCount != 1 {
		return false
	}

	return true
}

func (bug *Bug) Append(op Operation) {
	bug.Staging.Append(op)
}

func (bug *Bug) Commit() {
	bug.Packs = append(bug.Packs, bug.Staging)
	bug.Staging = OperationPack{}
}

func (bug *Bug) HumanId() string {
	return bug.Id.String()
}

func (bug *Bug) firstOp() Operation {
	for _, pack := range bug.Packs {
		for _, op := range pack.Operations {
			return op
		}
	}

	if !bug.Staging.IsEmpty() {
		return bug.Staging.Operations[0]
	}

	return nil
}