1use crate::{Context, ContextPeopleExt, IxaEvent, PersonId, PersonProperty};
2use ixa_derive::IxaEvent;
3
4#[derive(Clone, Copy, IxaEvent)]
7#[allow(clippy::manual_non_exhaustive)]
8pub struct PersonCreatedEvent {
9 pub person_id: PersonId,
11}
12
13#[derive(Copy, Clone)]
16#[allow(clippy::manual_non_exhaustive)]
17pub struct PersonPropertyChangeEvent<T: PersonProperty> {
18 pub person_id: PersonId,
20 pub current: T::Value,
22 pub previous: T::Value,
24}
25
26impl<T: PersonProperty> IxaEvent for PersonPropertyChangeEvent<T> {
27 fn on_subscribe(context: &mut Context) {
28 if T::is_derived() {
29 context.register_property::<T>();
30 }
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use crate::{
37 define_derived_property, define_global_property, define_person_property,
38 define_person_property_with_default, Context, ContextPeopleExt, PersonCreatedEvent,
39 PersonId, PersonPropertyChangeEvent,
40 };
41 use serde_derive::Serialize;
42 use std::cell::RefCell;
43 use std::rc::Rc;
44
45 define_person_property!(Age, u8);
46 #[derive(Serialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
47 pub enum AgeGroupValue {
48 Child,
49 Adult,
50 }
51 define_global_property!(Threshold, u8);
52
53 define_derived_property!(AgeGroup, AgeGroupValue, [Age], |age| {
54 if age < 18 {
55 AgeGroupValue::Child
56 } else {
57 AgeGroupValue::Adult
58 }
59 });
60
61 #[derive(Serialize, Copy, Clone, PartialEq, Eq, Debug)]
62 pub enum RiskCategoryValue {
63 High,
64 Low,
65 }
66 define_person_property!(RiskCategory, RiskCategoryValue);
67 define_person_property_with_default!(IsRunner, bool, false);
68 define_person_property!(RunningShoes, u8, |context: &Context, person: PersonId| {
69 let is_runner = context.get_person_property(person, IsRunner);
70 if is_runner {
71 4
72 } else {
73 0
74 }
75 });
76
77 #[test]
78 fn observe_person_addition() {
79 let mut context = Context::new();
80
81 let flag = Rc::new(RefCell::new(false));
82 let flag_clone = flag.clone();
83 context.subscribe_to_event(move |_context, event: PersonCreatedEvent| {
84 *flag_clone.borrow_mut() = true;
85 assert_eq!(event.person_id.0, 0);
86 });
87
88 let _ = context.add_person(()).unwrap();
89 context.execute();
90 assert!(*flag.borrow());
91 }
92
93 #[test]
94 fn observe_person_property_change() {
95 let mut context = Context::new();
96
97 let flag = Rc::new(RefCell::new(false));
98 let flag_clone = flag.clone();
99 context.subscribe_to_event(
100 move |_context, event: PersonPropertyChangeEvent<RiskCategory>| {
101 *flag_clone.borrow_mut() = true;
102 assert_eq!(event.person_id.0, 0, "Person id is correct");
103 assert_eq!(
104 event.previous,
105 RiskCategoryValue::Low,
106 "Previous value is correct"
107 );
108 assert_eq!(
109 event.current,
110 RiskCategoryValue::High,
111 "Current value is correct"
112 );
113 },
114 );
115 let person_id = context
116 .add_person((RiskCategory, RiskCategoryValue::Low))
117 .unwrap();
118 context.set_person_property(person_id, RiskCategory, RiskCategoryValue::High);
119 context.execute();
120 assert!(*flag.borrow());
121 }
122
123 #[test]
124 fn observe_person_property_change_with_set() {
125 let mut context = Context::new();
126
127 let flag = Rc::new(RefCell::new(false));
128 let flag_clone = flag.clone();
129 context.subscribe_to_event(
130 move |_context, _event: PersonPropertyChangeEvent<RunningShoes>| {
131 *flag_clone.borrow_mut() = true;
132 },
133 );
134 let person_id = context.add_person(()).unwrap();
135 context.set_person_property(person_id, RunningShoes, 42);
137 context.execute();
138 assert!(*flag.borrow());
139 }
140
141 #[test]
142 fn get_person_property_change_event() {
143 let mut context = Context::new();
144 let person = context.add_person((Age, 17)).unwrap();
145
146 let flag = Rc::new(RefCell::new(false));
147
148 let flag_clone = flag.clone();
149 context.subscribe_to_event(
150 move |_context, event: PersonPropertyChangeEvent<AgeGroup>| {
151 assert_eq!(event.person_id.0, 0);
152 assert_eq!(event.previous, AgeGroupValue::Child);
153 assert_eq!(event.current, AgeGroupValue::Adult);
154 *flag_clone.borrow_mut() = true;
155 },
156 );
157 context.set_person_property(person, Age, 18);
158 context.execute();
159 assert!(*flag.borrow());
160 }
161
162 #[test]
163 fn test_person_property_change_event_no_people() {
164 let mut context = Context::new();
165 context.subscribe_to_event(|_context, _event: PersonPropertyChangeEvent<IsRunner>| {
167 unreachable!();
168 });
169
170 context.subscribe_to_event(|_context, _event: PersonPropertyChangeEvent<AgeGroup>| {
172 unreachable!();
173 });
174 }
175}