use crate::domain::model::decision_record::{DecisionRecord, DecisionRecordCollection};
use crate::domain::model::issue::companion::{
CompanionContent, CompanionIdentifier, IssueCompanions,
};
use crate::domain::model::issue::{Issue, IssueCollection};
use crate::domain::model::record_ref::{DecisionRecordRef, IssueRef};
use crate::domain::usecases::decision_record::DecisionRecordRepository;
use crate::domain::usecases::issue::IssueRepository;
pub struct ReadOnlyIssueRepo<R> {
inner: R,
}
impl<R> ReadOnlyIssueRepo<R> {
pub fn new(inner: R) -> Self {
Self { inner }
}
}
impl<R: IssueRepository> IssueRepository for ReadOnlyIssueRepo<R> {
fn save(&self, _issue: &Issue) -> anyhow::Result<()> {
Ok(())
}
fn list(&self) -> anyhow::Result<IssueCollection> {
self.inner.list()
}
fn find_by_id(&self, id: &IssueRef) -> anyhow::Result<Option<Issue>> {
self.inner.find_by_id(id)
}
fn issue_companions(&self, id: &IssueRef) -> anyhow::Result<IssueCompanions> {
self.inner.issue_companions(id)
}
fn read_companion(
&self,
id: &IssueRef,
identifier: &CompanionIdentifier,
) -> anyhow::Result<Option<CompanionContent>> {
self.inner.read_companion(id, identifier)
}
fn configured_id_prefix(&self) -> Option<&str> {
self.inner.configured_id_prefix()
}
}
pub struct ReadOnlyDrRepo<R> {
inner: R,
}
impl<R> ReadOnlyDrRepo<R> {
pub fn new(inner: R) -> Self {
Self { inner }
}
}
impl<R: DecisionRecordRepository> DecisionRecordRepository for ReadOnlyDrRepo<R> {
fn save(&self, _record: &DecisionRecord) -> anyhow::Result<()> {
Ok(())
}
fn list(&self) -> anyhow::Result<DecisionRecordCollection> {
self.inner.list()
}
fn find_by_id(&self, id: &DecisionRecordRef) -> anyhow::Result<Option<DecisionRecord>> {
self.inner.find_by_id(id)
}
fn configured_id_prefix(&self) -> Option<&str> {
self.inner.configured_id_prefix()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::domain::model::decision_record::DrStatus;
use crate::domain::model::issue::test_fixtures::{make_issue, st};
use crate::domain::usecases::decision_record::test_support::make_record;
use std::cell::Cell;
struct StubIssueRepo {
save_calls: Cell<usize>,
list_calls: Cell<usize>,
issues: Vec<Issue>,
}
impl IssueRepository for StubIssueRepo {
fn save(&self, _issue: &Issue) -> anyhow::Result<()> {
self.save_calls.set(self.save_calls.get() + 1);
Ok(())
}
fn list(&self) -> anyhow::Result<IssueCollection> {
self.list_calls.set(self.list_calls.get() + 1);
Ok(IssueCollection::new(self.issues.clone()))
}
fn find_by_id(&self, _id: &IssueRef) -> anyhow::Result<Option<Issue>> {
Ok(None)
}
fn issue_companions(&self, _id: &IssueRef) -> anyhow::Result<IssueCompanions> {
Ok(IssueCompanions::new())
}
fn read_companion(
&self,
_id: &IssueRef,
_identifier: &CompanionIdentifier,
) -> anyhow::Result<Option<CompanionContent>> {
Ok(None)
}
fn configured_id_prefix(&self) -> Option<&str> {
Some("ISSUE-")
}
}
fn issue_stub(issues: Vec<Issue>) -> StubIssueRepo {
StubIssueRepo {
save_calls: Cell::new(0),
list_calls: Cell::new(0),
issues,
}
}
#[test]
fn save_on_decorator_does_not_reach_inner_repo() {
let issue = make_issue(1, "t", st("open"));
let ro = ReadOnlyIssueRepo::new(issue_stub(vec![]));
ro.save(&issue).unwrap();
ro.save(&issue).unwrap();
assert_eq!(ro.inner.save_calls.get(), 0);
}
#[test]
fn reads_delegate_to_inner_repo() {
let issue = make_issue(1, "t", st("open"));
let ro = ReadOnlyIssueRepo::new(issue_stub(vec![issue]));
assert_eq!(ro.list().unwrap().len(), 1);
assert_eq!(ro.inner.list_calls.get(), 1);
assert_eq!(ro.configured_id_prefix(), Some("ISSUE-"));
}
struct StubDrRepo {
save_calls: Cell<usize>,
records: Vec<DecisionRecord>,
}
impl DecisionRecordRepository for StubDrRepo {
fn save(&self, _record: &DecisionRecord) -> anyhow::Result<()> {
self.save_calls.set(self.save_calls.get() + 1);
Ok(())
}
fn list(&self) -> anyhow::Result<DecisionRecordCollection> {
Ok(DecisionRecordCollection::new(self.records.clone()))
}
fn find_by_id(&self, _id: &DecisionRecordRef) -> anyhow::Result<Option<DecisionRecord>> {
Ok(None)
}
fn configured_id_prefix(&self) -> Option<&str> {
Some("ADR-")
}
}
fn dr_stub(records: Vec<DecisionRecord>) -> StubDrRepo {
StubDrRepo {
save_calls: Cell::new(0),
records,
}
}
#[test]
fn dr_save_on_decorator_is_silenced() {
let dr = make_record(1, "t", DrStatus::Proposed);
let ro = ReadOnlyDrRepo::new(dr_stub(vec![]));
ro.save(&dr).unwrap();
assert_eq!(ro.inner.save_calls.get(), 0);
}
#[test]
fn dr_reads_delegate_to_inner_repo() {
let dr = make_record(1, "t", DrStatus::Proposed);
let ro = ReadOnlyDrRepo::new(dr_stub(vec![dr]));
assert_eq!(ro.list().unwrap().len(), 1);
assert_eq!(ro.configured_id_prefix(), Some("ADR-"));
}
}