52 lines
1.2 KiB
Go
52 lines
1.2 KiB
Go
package domain
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"git.cin.su/m/Assistant/contracts/authority"
|
|
contract "git.cin.su/m/Assistant/contracts/work"
|
|
)
|
|
|
|
var (
|
|
ErrTaskNotFound = errors.New("task not found")
|
|
ErrTaskTargetMismatch = errors.New("task target does not match canonical task")
|
|
ErrRevisionConflict = errors.New("task revision conflict")
|
|
)
|
|
|
|
type Task struct {
|
|
ID contract.TaskID
|
|
GoalID contract.GoalID
|
|
ScopeID authority.ScopeID
|
|
Revision contract.TaskRevision
|
|
}
|
|
|
|
// Store models owner-local task state for the walking skeleton. A caller must
|
|
// present all target integrity fields; no cross-owner lookup is performed.
|
|
type Store struct {
|
|
tasks map[contract.TaskID]Task
|
|
}
|
|
|
|
func NewStore(tasks []Task) Store {
|
|
stored := make(map[contract.TaskID]Task, len(tasks))
|
|
for _, task := range tasks {
|
|
stored[task.ID] = task
|
|
}
|
|
return Store{tasks: stored}
|
|
}
|
|
|
|
func (s *Store) Commit(target contract.TaskTarget) (Task, error) {
|
|
task, ok := s.tasks[target.TaskID]
|
|
if !ok {
|
|
return Task{}, ErrTaskNotFound
|
|
}
|
|
if task.GoalID != target.GoalID || task.ScopeID != target.ScopeID {
|
|
return Task{}, ErrTaskTargetMismatch
|
|
}
|
|
if task.Revision != target.Revision {
|
|
return Task{}, ErrRevisionConflict
|
|
}
|
|
task.Revision++
|
|
s.tasks[task.ID] = task
|
|
return task, nil
|
|
}
|