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