2 unstable releases

0.2.0 Mar 1, 2021
0.1.0 Feb 26, 2021

#1775 in Asynchronous

MIT license

13KB
170 lines

Crates.io Docs.rs MIT licensed

causality

"the relation between a cause and its effect or between regularly correlated events or phenomena"

Merriam-Webster

Event Driven Architecture Traits.

Prescriptive implementation of event sourcing models.

Usage example in documentation.

Documentation

cargo doc --open

References

License

MIT


lib.rs:

Traits for implementing Event Driven Architectures.

Borrowing with fervor from the Theory of Causality to conceptualize deterministic state.

Ideas represented are often a reflection off of the work of others (Causality, Event Sourcing, CQRS, etc).

CAUTION: Implementation hasn't had time to mature. Expect breaking changes.

Example

use simple_error::SimpleError;
use causality::{Actor, Cause, Effect};

enum Command {
    TestDoor {actor_id: u32, actor_version: u8},
}

impl Cause for Command {
    type ActorId = u32;
    type ActorVersion = u8;
    fn actor_id(&self) -> Self::ActorId {
        match self {
            Command::TestDoor {actor_id, ..} => {
                *actor_id
            }
        }
    }
    fn actor_version(&self) -> Self::ActorVersion {
        match self {
            Command::TestDoor {actor_version, ..} => {
                *actor_version
            }
        }
    }
}

enum Event {
    Opened {version: u8, key: u32},
    Closed {version: u8, key: u32}
}

impl Effect for Event {
    type Version = u8;
    type Key = u32;
    fn version(&self) -> Self::Version {
        match self {
            Event::Opened {version, ..} |
            Event::Closed {version, ..} => {
                *version
            }
        }
    }
    fn key(&self) -> Self::Key {
        match self {
            Event::Opened {key, ..} |
            Event::Closed {key, ..} => {
                *key
            }
        }
    }
}

struct Door {
    id: u32,
    version: u8
}

impl Actor<Command, Event, SimpleError> for Door {
    type Id = u32;
    type Version = u8;
    fn handle(&self, command: Command) -> Result<Vec<Event>, SimpleError> {
        match command {
            Command::TestDoor {actor_id, actor_version} => {
                return Ok(vec![
                    Event::Opened {version: 1, key: 1},
                    Event::Closed {version: 1, key: 2}
                ]);
            }
        }
        Err(SimpleError::new("command should be found due to enum type"))
    }
    fn apply(&mut self, effects: Vec<Event>) -> Result<(), SimpleError> {
        for effect in effects {
            match effect {
                Event::Opened {key, ..} |
                Event::Closed {key, ..} => {
                    self.version = key as u8;
                }
            }
        }
        Ok(())
    }
}

let mut door = Door {
    id: 1,
    version: 1
};
let command = Command::TestDoor {
    actor_id: 1,
    actor_version: 1
};
let events = door.handle(command).unwrap();
assert_eq!(events.len(), 2);
let result = door.apply(events);
assert!(result.is_ok());

No runtime deps