refactor: clean up NodeService interface; move all integrity logic behind it
This commit is contained in:
@@ -5,14 +5,82 @@ import (
|
||||
"axolotl/store"
|
||||
)
|
||||
|
||||
// NodeService is the single entry point for all node operations.
|
||||
// All data-model integrity rules are enforced here; callers cannot produce
|
||||
// invalid state by interacting with this interface alone.
|
||||
type NodeService interface {
|
||||
Create(title, content, dueDate string, tags []string, rels map[models.RelType][]string) (*models.Node, error)
|
||||
Update(node *models.Node) error
|
||||
Delete(id string) error
|
||||
// Query
|
||||
GetByID(id string) (*models.Node, error)
|
||||
List(opts ...ListOption) ([]*models.Node, error)
|
||||
Exists(id string) (bool, error)
|
||||
CanClose(id string) (bool, []string, error)
|
||||
List(filter ListFilter) ([]*models.Node, error)
|
||||
|
||||
// Lifecycle
|
||||
Add(input AddInput) (*models.Node, error)
|
||||
Update(id string, input UpdateInput) (*models.Node, error)
|
||||
Delete(id string) error
|
||||
|
||||
// User management
|
||||
AddUser(name string) (*models.Node, error)
|
||||
ListUsers() ([]*models.Node, error)
|
||||
}
|
||||
|
||||
// AddInput describes a new node to create.
|
||||
type AddInput struct {
|
||||
Title string
|
||||
Content string
|
||||
DueDate string
|
||||
Type string // default: "issue"
|
||||
Status string // default: "open" when Type is "issue"
|
||||
Priority string
|
||||
// Namespace is a namespace name or node ID. Defaults to the current user.
|
||||
Namespace string
|
||||
// Assignee is a username or node ID.
|
||||
Assignee string
|
||||
// Tags are arbitrary user-defined labels (not system properties).
|
||||
Tags []string
|
||||
// Rels are additional typed edges (e.g. blocks, subtask, related).
|
||||
Rels []RelInput
|
||||
}
|
||||
|
||||
// UpdateInput describes changes to apply to an existing node.
|
||||
// Nil pointer fields mean "no change".
|
||||
type UpdateInput struct {
|
||||
Title *string
|
||||
Content *string
|
||||
DueDate *string // nil = no change; pointer to "" = clear due date
|
||||
// Status "done" is rejected when the node has open blockers.
|
||||
Status *string
|
||||
Priority *string
|
||||
Type *string
|
||||
// Namespace replaces the current namespace.
|
||||
Namespace *string
|
||||
// Assignee replaces the current assignee.
|
||||
Assignee *string
|
||||
AddTags []string
|
||||
RemoveTags []string
|
||||
AddRels []RelInput
|
||||
RemoveRels []RelInput
|
||||
}
|
||||
|
||||
// ListFilter specifies which nodes to return. Empty fields are ignored.
|
||||
type ListFilter struct {
|
||||
Tags []string
|
||||
Status string
|
||||
Priority string
|
||||
Type string
|
||||
// Namespace filters by namespace name or node ID.
|
||||
Namespace string
|
||||
// Assignee filters by username or node ID.
|
||||
Assignee string
|
||||
// Mention filters to nodes that mention the given username or node ID.
|
||||
Mention string
|
||||
// Rels are additional relation filters (e.g. blocks:someID).
|
||||
Rels []RelInput
|
||||
}
|
||||
|
||||
// RelInput is a typed, directed edge with a target that may be a name or node ID.
|
||||
type RelInput struct {
|
||||
Type models.RelType
|
||||
Target string // name or node ID; the service resolves names
|
||||
}
|
||||
|
||||
func InitNodeService(path string) error {
|
||||
@@ -26,18 +94,3 @@ func GetNodeService(cfg Config) (NodeService, error) {
|
||||
}
|
||||
return &nodeServiceImpl{store: st, userID: cfg.GetUser()}, nil
|
||||
}
|
||||
|
||||
type listFilter struct {
|
||||
tagPrefixes []string
|
||||
relPrefixes []*models.Rel
|
||||
}
|
||||
|
||||
type ListOption func(*listFilter)
|
||||
|
||||
func WithTags(prefixes ...string) ListOption {
|
||||
return func(f *listFilter) { f.tagPrefixes = append(f.tagPrefixes, prefixes...) }
|
||||
}
|
||||
|
||||
func WithRels(prefixes ...*models.Rel) ListOption {
|
||||
return func(f *listFilter) { f.relPrefixes = append(f.relPrefixes, prefixes...) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user