CoreExpression.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. using Expressive;
  2. using Expressive.Expressions;
  3. using Expressive.Functions;
  4. using InABox.Clients;
  5. using JetBrains.Annotations;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Diagnostics.CodeAnalysis;
  9. using System.Linq;
  10. using System.Text;
  11. namespace InABox.Core
  12. {
  13. using FncType = Func<IExpression[], IDictionary<string, object>, object?>;
  14. public class CoreExpressionFunction
  15. {
  16. public string Group { get; set; }
  17. public string Name { get; set; }
  18. public List<string> Parameters { get; set; }
  19. public FncType Function { get; set; }
  20. public CoreExpressionFunction(string group, string name, FncType function, List<string> parameters)
  21. {
  22. Group = group;
  23. Name = name;
  24. Parameters = parameters;
  25. Function = function;
  26. }
  27. }
  28. public interface IExpressionModel { }
  29. public interface IExpressionModel<TReturn> : IExpressionModel { }
  30. public class CoreExpression
  31. {
  32. private Expression Expression;
  33. public IReadOnlyCollection<string> ReferencedVariables => Expression.ReferencedVariables;
  34. protected virtual Type? ReturnType { get; }
  35. public CoreExpression(string expressionString)
  36. {
  37. Expression = new Expression(expressionString);
  38. foreach (var function in Functions)
  39. {
  40. Expression.RegisterFunction(function.Name, function.Function);
  41. }
  42. }
  43. public object? Evaluate(Dictionary<string, object?>? variables)
  44. {
  45. var result = Expression.Evaluate(variables);
  46. if(ReturnType != null)
  47. {
  48. return CoreUtils.ChangeType(result, ReturnType);
  49. }
  50. return result;
  51. }
  52. public static List<string> GetModelVariables(Type modelType)
  53. {
  54. return CoreUtils.PropertyList(modelType, x => true).Select(x => x.Name).ToList();
  55. }
  56. public static List<string> GetModelVariables<TModel>() where TModel : IExpressionModel
  57. => GetModelVariables(typeof(TModel));
  58. #region Static
  59. public static List<CoreExpressionFunction> Functions = new List<CoreExpressionFunction>();
  60. static CoreExpression()
  61. {
  62. RegisterFunction("String", "Format", (p, v) =>
  63. {
  64. if (!(p[0].Evaluate(v) is string format)) throw new Exception("No format string given for Format()");
  65. return string.Format(format, p.Skip(1).Select(x => x.Evaluate(v)).ToArray());
  66. }, "fmt", "...");
  67. RegisterFunction("Other", "Client_LoadDocument", Fnc_LoadDocument, "docID");
  68. }
  69. private static object? Fnc_LoadDocument(IExpression[] p, IDictionary<string, object> v)
  70. {
  71. var id = p[0].Evaluate(v);
  72. if (id is null)
  73. return null;
  74. if (!(id is Guid docID))
  75. return null;
  76. return new Client<Document>()
  77. .Query(
  78. new Filter<Document>(x => x.ID).IsEqualTo(docID),
  79. new Columns<Document>(x => x.Data))
  80. .Rows.FirstOrDefault()
  81. ?.Get<Document, byte[]>(x => x.Data);
  82. }
  83. public static void RegisterFunction(string group, string name, FncType function, params string[] parameters) =>
  84. Functions.Add(new CoreExpressionFunction(group, name, function, parameters.ToList()));
  85. #endregion
  86. }
  87. public class CoreExpression<TModel, TReturn> : CoreExpression
  88. where TModel : IExpressionModel<TReturn>
  89. {
  90. protected override Type? ReturnType => typeof(TReturn);
  91. public CoreExpression(string expressionString): base(expressionString) { }
  92. [return: MaybeNull]
  93. public new TReturn Evaluate(Dictionary<string, object?>? variables)
  94. {
  95. var result = base.Evaluate(variables);
  96. if(result is TReturn ret)
  97. {
  98. return ret;
  99. }
  100. return default;
  101. }
  102. [return: MaybeNull]
  103. public TReturn Evaluate(TModel model)
  104. {
  105. var values = new Dictionary<string, object?>();
  106. foreach(var variable in ReferencedVariables)
  107. {
  108. values[variable] = CoreUtils.GetPropertyValue(model, variable);
  109. }
  110. var result = base.Evaluate(values);
  111. if(result is TReturn ret)
  112. {
  113. return ret;
  114. }
  115. return default;
  116. }
  117. }
  118. }