use crate::builder::node::NodeBuilder;
use crate::intent_graph::{
DagStage, ExtendedNodeType, Node, NodeType, Status,
};
pub struct StoryBuilder(NodeBuilder);
impl StoryBuilder {
#[must_use]
pub fn new() -> Self {
Self(
NodeBuilder::new()
.node_type(NodeType::Story)
.dag_stage(DagStage::Feature)
.status(Status::Active)
.with_meta("agileplus-ontology-ext"),
)
}
pub fn id(mut self, id: impl Into<String>) -> Self {
self.0 = self.0.id(id);
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.0 = self.0.title(title);
self
}
pub fn status(mut self, status: Status) -> Self {
self.0 = self.0.status(status);
self
}
pub fn tag(mut self, tag: impl Into<String>) -> Self {
self.0 = self.0.tag(tag);
self
}
pub fn description(mut self, desc: impl Into<String>) -> Self {
self.0 = self.0.description(desc);
self
}
pub fn build(self) -> Result<Node, String> {
self.0.build()
}
}
impl Default for StoryBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct BugBuilder(NodeBuilder);
impl BugBuilder {
#[must_use]
pub fn new() -> Self {
Self(
NodeBuilder::new()
.node_type(NodeType::Bug)
.dag_stage(DagStage::Task)
.status(Status::Active)
.with_meta("agileplus-ontology-ext"),
)
}
pub fn id(mut self, id: impl Into<String>) -> Self {
self.0 = self.0.id(id);
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.0 = self.0.title(title);
self
}
pub fn status(mut self, status: Status) -> Self {
self.0 = self.0.status(status);
self
}
pub fn tag(mut self, tag: impl Into<String>) -> Self {
self.0 = self.0.tag(tag);
self
}
pub fn description(mut self, desc: impl Into<String>) -> Self {
self.0 = self.0.description(desc);
self
}
pub fn build(self) -> Result<Node, String> {
self.0.build()
}
}
impl Default for BugBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct MetricBuilder(NodeBuilder);
impl MetricBuilder {
#[must_use]
pub fn new() -> Self {
Self(
NodeBuilder::new()
.node_type(NodeType::Artifact)
.dag_stage(DagStage::Intent)
.status(Status::Active)
.with_meta("agileplus-ontology-ext"),
)
}
pub fn id(mut self, id: impl Into<String>) -> Self {
self.0 = self.0.id(id);
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.0 = self.0.title(title);
self
}
pub fn status(mut self, status: Status) -> Self {
self.0 = self.0.status(status);
self
}
pub fn tag(mut self, tag: impl Into<String>) -> Self {
self.0 = self.0.tag(tag);
self
}
pub fn description(mut self, desc: impl Into<String>) -> Self {
self.0 = self.0.description(desc);
self
}
pub fn build(self) -> Result<Node, String> {
self.0.build()
}
}
impl Default for MetricBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct HypothesisBuilder(NodeBuilder);
impl HypothesisBuilder {
#[must_use]
pub fn new() -> Self {
Self(
NodeBuilder::new()
.node_type(NodeType::Intent)
.dag_stage(DagStage::Intent)
.status(Status::Active)
.with_meta("agileplus-ontology-ext"),
)
}
pub fn id(mut self, id: impl Into<String>) -> Self {
self.0 = self.0.id(id);
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.0 = self.0.title(title);
self
}
pub fn status(mut self, status: Status) -> Self {
self.0 = self.0.status(status);
self
}
pub fn tag(mut self, tag: impl Into<String>) -> Self {
self.0 = self.0.tag(tag);
self
}
pub fn description(mut self, desc: impl Into<String>) -> Self {
self.0 = self.0.description(desc);
self
}
pub fn build(self) -> Result<Node, String> {
self.0.build()
}
}
impl Default for HypothesisBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct ExtendedNodeBuilder {
variant: ExtendedNodeType,
inner: NodeBuilder,
}
impl ExtendedNodeBuilder {
#[must_use]
pub fn new(variant: ExtendedNodeType) -> Self {
Self {
variant,
inner: NodeBuilder::new()
.node_type(variant.as_core_node_type())
.dag_stage(variant.dag_stage())
.status(Status::Active)
.with_meta("agileplus-ontology-ext"),
}
}
#[must_use]
pub fn variant(&self) -> ExtendedNodeType {
self.variant
}
pub fn id(mut self, id: impl Into<String>) -> Self {
self.inner = self.inner.id(id);
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.inner = self.inner.title(title);
self
}
pub fn description(mut self, desc: impl Into<String>) -> Self {
self.inner = self.inner.description(desc);
self
}
pub fn status(mut self, status: Status) -> Self {
self.inner = self.inner.status(status);
self
}
pub fn tag(mut self, tag: impl Into<String>) -> Self {
self.inner = self.inner.tag(tag);
self
}
pub fn build(self) -> Result<Node, String> {
self.inner.build()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn story_builder_applies_defaults() {
let n = StoryBuilder::new()
.id("Story#user-auth")
.title("User auth")
.build()
.unwrap();
assert_eq!(n.node_type, NodeType::Story);
assert_eq!(n.dag_stage, DagStage::Feature);
assert_eq!(n.status, Status::Active);
assert_eq!(n.meta.source, "agileplus-ontology-ext");
}
#[test]
fn bug_builder_applies_defaults() {
let n = BugBuilder::new()
.id("Bug#login-crash")
.title("Login crashes")
.build()
.unwrap();
assert_eq!(n.node_type, NodeType::Bug);
assert_eq!(n.dag_stage, DagStage::Task);
}
#[test]
fn metric_and_hypothesis_builders_apply_intent_stage() {
let m = MetricBuilder::new()
.id("Metric#latency-p99")
.title("p99 latency")
.build()
.unwrap();
assert_eq!(m.dag_stage, DagStage::Intent);
let h = HypothesisBuilder::new()
.id("Hypothesis#cache-helps")
.title("Cache helps p99")
.build()
.unwrap();
assert_eq!(h.dag_stage, DagStage::Intent);
}
#[test]
fn extended_node_builder_round_trip() {
for v in [
ExtendedNodeType::Story,
ExtendedNodeType::Bug,
ExtendedNodeType::Metric,
ExtendedNodeType::Hypothesis,
] {
let builder = ExtendedNodeBuilder::new(v);
assert_eq!(builder.variant(), v);
}
}
}