SaveEvent.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. using Comal.Classes;
  2. using InABox.Core;
  3. using InABox.Scripting;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics.CodeAnalysis;
  7. using System.Linq;
  8. using System.Text;
  9. namespace PRS.Shared.Events;
  10. public class SaveEvent<T> : IEvent<SaveEventDataModel<T>>
  11. where T : Entity
  12. {
  13. public Type Entity => typeof(T);
  14. public IEventDataModelDefinition DataModelDefinition()
  15. {
  16. return new SaveEventDataModelDefinition<T>(this);
  17. }
  18. public Notification GenerateNotification(SaveEventDataModel<T> model)
  19. {
  20. var notification = new Notification();
  21. notification.Title = $"Updated {typeof(T).Name}";
  22. notification.Description = $"Updated {typeof(T).Name}";
  23. if(model.Entity.ID != Guid.Empty)
  24. {
  25. notification.EntityType = CoreUtils.EntityName(model.EntityType);
  26. notification.EntityID = model.Entity.ID;
  27. }
  28. return notification;
  29. }
  30. }
  31. public class SaveEventDataModelDefinition<T>(SaveEvent<T> ev) : IEventDataModelDefinition
  32. where T : Entity
  33. {
  34. private IEventVariable[]? variables;
  35. public SaveEvent<T> Event { get; set; } = ev;
  36. public IEnumerable<IEventVariable> GetVariables()
  37. {
  38. if(variables is null)
  39. {
  40. variables = DatabaseSchema.AllProperties(Event.Entity).Select(x => new StandardEventVariable(x.Name, x.PropertyType)).ToArray();
  41. variables.SortBy(x => x.Name);
  42. }
  43. return variables;
  44. }
  45. public IEventVariable? GetVariable(string name)
  46. {
  47. if(variables is null)
  48. {
  49. var prop = DatabaseSchema.Property(Event.Entity, name);
  50. if(prop is null)
  51. {
  52. return null;
  53. }
  54. else
  55. {
  56. return new StandardEventVariable(prop.Name, prop.PropertyType);
  57. }
  58. }
  59. else
  60. {
  61. return variables.FirstOrDefault(x => x.Name == name);
  62. }
  63. }
  64. }
  65. public class SaveEventDataModel<T>(T entity) : IEventDataModel, ITypedEventDataModel
  66. where T : Entity
  67. {
  68. public T Entity { get; set; } = entity;
  69. public Type EntityType => typeof(T);
  70. public bool TryGetVariable(string name, out object? value)
  71. {
  72. var prop = DatabaseSchema.Property(typeof(T), name);
  73. if(prop != null)
  74. {
  75. value = prop.Getter()(Entity);
  76. return true;
  77. }
  78. else
  79. {
  80. value = null;
  81. return false;
  82. }
  83. }
  84. }
  85. #region Triggers
  86. public class CreatedSaveEventTrigger<T> : ITrigger<SaveEvent<T>, SaveEventDataModel<T>>
  87. where T : Entity
  88. {
  89. public bool Check(SaveEventDataModel<T> dataModel)
  90. {
  91. return dataModel.Entity.HasOriginalValue(x => x.ID);
  92. }
  93. }
  94. public class PropertyChangedSaveEventTrigger<T> : ITrigger<SaveEvent<T>, SaveEventDataModel<T>>
  95. where T : Entity
  96. {
  97. public IProperty? TriggerProperty { get; set; }
  98. public object? OldValue { get; set; }
  99. public object? NewValue { get; set; }
  100. public bool Check(SaveEventDataModel<T> dataModel)
  101. {
  102. if(TriggerProperty is null)
  103. {
  104. return false;
  105. }
  106. if (!dataModel.Entity.HasOriginalValue(TriggerProperty.Name))
  107. {
  108. return false;
  109. }
  110. if(OldValue is not null && !object.Equals(dataModel.Entity.OriginalValueList[TriggerProperty.Name], OldValue))
  111. {
  112. return false;
  113. }
  114. if(NewValue is not null && !object.Equals(TriggerProperty.Getter()(dataModel.Entity), NewValue))
  115. {
  116. return false;
  117. }
  118. return true;
  119. }
  120. }
  121. public class ScriptSaveEventTrigger<T> : ITrigger<SaveEvent<T>, SaveEventDataModel<T>>
  122. where T : Entity
  123. {
  124. private ScriptDocument? _scriptDocument;
  125. private string? _script;
  126. public string? Script
  127. {
  128. get => _script;
  129. set
  130. {
  131. if(_script != value)
  132. {
  133. _script = value;
  134. _scriptDocument = null;
  135. }
  136. }
  137. }
  138. public string DefaultScript()
  139. {
  140. return @"
  141. using Comal.Classes;
  142. public class Module
  143. {
  144. public bool Check(SaveEventDataModel<" + typeof(T).Name + @"> model)
  145. {
  146. // Return true if model.Entity meets the requirements for this event trigger.
  147. return true;
  148. }
  149. }";
  150. }
  151. public bool Check(SaveEventDataModel<T> dataModel)
  152. {
  153. if (Script is null) return false;
  154. if(_scriptDocument is null)
  155. {
  156. _scriptDocument = new(Script);
  157. _scriptDocument.Compile();
  158. }
  159. return _scriptDocument.Execute(methodname: "Check", parameters: [dataModel]);
  160. }
  161. }
  162. #endregion
  163. #region Actions
  164. public class ScriptSaveEventAction<T> : IEventAction<SaveEvent<T>>
  165. where T : Entity
  166. {
  167. private ScriptDocument? _scriptDocument;
  168. private string? _script;
  169. public string? Script
  170. {
  171. get => _script;
  172. set
  173. {
  174. if(_script != value)
  175. {
  176. _script = value;
  177. _scriptDocument = null;
  178. }
  179. }
  180. }
  181. public string DefaultScript()
  182. {
  183. return @"
  184. using Comal.Classes;
  185. public class Module
  186. {
  187. public object? Result { get; set; }
  188. public bool Execute(SaveEventDataModel<" + typeof(T).Name + @"> model)
  189. {
  190. // Do anything you want with model.Entity, and then save return-value to 'Result', or leave it as 'null' if no return value is needed.
  191. return true;
  192. }
  193. }";
  194. }
  195. public object? Execute(IEventDataModel dataModel)
  196. {
  197. if (Script is null) return null;
  198. if(_scriptDocument is null)
  199. {
  200. _scriptDocument = new(Script);
  201. _scriptDocument.SetValue("Result", null);
  202. _scriptDocument.Compile();
  203. }
  204. var model = dataModel.RootModel<SaveEventDataModel<T>>();
  205. if(_scriptDocument.Execute(methodname: "Execute", parameters: [model]))
  206. {
  207. return _scriptDocument.GetValue("Result");
  208. }
  209. else
  210. {
  211. return null;
  212. }
  213. }
  214. public IEnumerable<string> ReferencedVariables()
  215. {
  216. yield break;
  217. }
  218. }
  219. public class CreateEntityAction<T> : IEventAction<SaveEvent<T>>
  220. where T : Entity
  221. {
  222. public Type? EntityType { get; set; }
  223. public List<PropertyInitializer> Initializers { get; set; } = new List<PropertyInitializer>();
  224. public object? Execute(IEventDataModel dataModel)
  225. {
  226. if(EntityType is null)
  227. {
  228. return null;
  229. }
  230. var entity = (Activator.CreateInstance(EntityType) as Entity)!;
  231. foreach(var initializer in Initializers)
  232. {
  233. initializer.Execute(entity, dataModel);
  234. }
  235. return entity;
  236. }
  237. public IEnumerable<string> ReferencedVariables()
  238. {
  239. return Initializers.SelectMany(x => x.ReferencedVariables());
  240. }
  241. }
  242. public class PropertyInitializer
  243. {
  244. public IProperty Property { get; set; }
  245. private CoreExpression? _valueExpression;
  246. private CoreExpression ValueExpression
  247. {
  248. get
  249. {
  250. _valueExpression ??= new CoreExpression(Value, Property.PropertyType);
  251. return _valueExpression;
  252. }
  253. }
  254. private string _value;
  255. public string Value
  256. {
  257. get => _value;
  258. [MemberNotNull(nameof(_value))]
  259. set
  260. {
  261. if(value != _value)
  262. {
  263. _value = value;
  264. _valueExpression = null;
  265. }
  266. }
  267. }
  268. public PropertyInitializer(IProperty property, string value)
  269. {
  270. Property = property;
  271. Value = value;
  272. }
  273. public void Execute(Entity entity, IEventDataModel dataModel)
  274. {
  275. Property.Setter()(entity, ValueExpression.Evaluate(dataModel));
  276. }
  277. public IEnumerable<string> ReferencedVariables()
  278. {
  279. return ValueExpression.ReferencedVariables;
  280. }
  281. }
  282. #endregion