package service import ( "axolotl/models" "axolotl/store" "fmt" ) // 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. // // Every NodeService instance is bound to a specific user (see User()). // GetNodeService returns an error when no user is configured. type NodeService interface { // User returns the name/ID of the user this service instance acts on behalf of. User() string // Query GetByID(id string) (*models.Node, 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. // Rels may contain tag rels (Target == ""), property rels (Target == "", // Type is "prefix::value"), and edge rels (Target is a node name or ID). // The service applies defaults (type=issue, status=open for issues) and validates. type AddInput struct { Title string Content string DueDate string Rels []RelInput } // UpdateInput describes changes to apply to an existing node. // AddRels and RemoveRels accept both tag rels (Target == "") and edge rels. // Setting _status::done in AddRels is rejected when the node has open blockers. // Adding assignee or in_namespace rels replaces the previous single target. type UpdateInput struct { Title *string Content *string DueDate *string // nil = no change; pointer to "" = clear due date AddRels []RelInput RemoveRels []RelInput } // ListFilter specifies which nodes to return. Empty slices are ignored. // Tag filters (Target == "") match by rel_name prefix. // Edge filters (Target != "") are resolved to node IDs. type ListFilter struct { Rels []RelInput } // RelInput is a typed, directed rel with a target that may be a name or node ID. // Target == "" means this is a tag or property rel (no target node). type RelInput struct { Type models.RelType Target string // name or node ID; the service resolves names. Empty = tag rel. } func InitNodeService(path string) error { return store.InitSQLiteStore(path) } func GetNodeService(cfg Config) (NodeService, error) { user := cfg.GetUser() if user == "" { return nil, fmt.Errorf("no user configured: run 'ax user set ' first") } st, err := store.FindAndOpenSQLiteStore() if err != nil { return nil, err } return &nodeServiceImpl{store: st, userID: user}, nil }