1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//! Repository ports.
//!
//! These are honest *documentation markers*: they tie a port to the aggregate it
//! persists (living documentation) and pin the `Send + Sync` `dyn` shape, but
//! prescribe no CRUD. The concrete methods live on the leaf trait in the
//! consuming application, where the argument types (the aggregate's typed id) are
//! known. Both are object-safe: associated type only, no methods.
use AggregateRoot;
/// A port that persists and retrieves a single aggregate.
///
/// # Examples
///
/// A leaf port extends `Repository` to declare *which* aggregate it owns, then
/// adds the actual CRUD:
///
/// ```
/// use ev_lib::architecture::{AggregateRoot, Entity, Id, Reader, Repository};
///
/// struct BlogTag;
/// type BlogId = Id<BlogTag>;
/// struct Blog {
/// id: BlogId,
/// }
/// impl Entity for Blog {
/// type Id = BlogId;
/// fn id(&self) -> BlogId {
/// self.id
/// }
/// }
/// impl AggregateRoot for Blog {
/// const NAME: &'static str = "blog";
/// }
///
/// trait BlogRepository: Repository<Aggregate = Blog> + Reader<Aggregate = Blog> {
/// fn create(&self, blog: Blog);
/// fn find(&self, id: BlogId) -> Option<Blog>;
/// }
///
/// // The marker keeps the port object-safe, so it can be held as a trait object.
/// fn _accepts_dyn(_: &dyn Repository<Aggregate = Blog>) {}
/// ```
/// The read-only half (ISP / CQRS): query handlers can depend on the narrow read
/// port without write power.