| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 | using Expressive;using Expressive.Expressions;using Expressive.Functions;using InABox.Clients;using JetBrains.Annotations;using System;using System.Collections.Generic;using System.Diagnostics.CodeAnalysis;using System.Linq;using System.Text;namespace InABox.Core{    using FncType = Func<IExpression[], IDictionary<string, object>, object?>;    public class CoreExpressionFunction    {        public string Group { get; set; }        public string Name { get; set; }        public List<string> Parameters { get; set; }        public FncType Function { get; set; }        public CoreExpressionFunction(string group, string name, FncType function, List<string> parameters)        {            Group = group;            Name = name;            Parameters = parameters;            Function = function;        }    }    public interface IExpressionModel { }    public interface IExpressionModel<TReturn> : IExpressionModel { }    public class CoreExpression    {        private Expression Expression;        public IReadOnlyCollection<string> ReferencedVariables => Expression.ReferencedVariables;        protected virtual Type? ReturnType { get; }        public CoreExpression(string expressionString)        {            Expression = new Expression(expressionString);            foreach (var function in Functions)            {                Expression.RegisterFunction(function.Name, function.Function);            }        }        public object? Evaluate(Dictionary<string, object?>? variables)        {            var result = Expression.Evaluate(variables);            if(ReturnType != null)            {                return CoreUtils.ChangeType(result, ReturnType);            }            return result;        }        public static List<string> GetModelVariables(Type modelType)        {            return CoreUtils.PropertyList(modelType, x => true).Select(x => x.Name).ToList();        }        public static List<string> GetModelVariables<TModel>() where TModel : IExpressionModel            => GetModelVariables(typeof(TModel));        #region Static        public static List<CoreExpressionFunction> Functions = new List<CoreExpressionFunction>();        static CoreExpression()        {            RegisterFunction("String", "Format", (p, v) =>            {                if (!(p[0].Evaluate(v) is string format)) throw new Exception("No format string given for Format()");                return string.Format(format, p.Skip(1).Select(x => x.Evaluate(v)).ToArray());            }, "fmt", "...");            RegisterFunction("Other", "Client_LoadDocument", Fnc_LoadDocument, "docID");        }        private static object? Fnc_LoadDocument(IExpression[] p, IDictionary<string, object> v)        {            var id = p[0].Evaluate(v);            if (id is null)                return null;            if (!(id is Guid docID))                return null;            return new Client<Document>()                .Query(                    new Filter<Document>(x => x.ID).IsEqualTo(docID),                    new Columns<Document>(x => x.Data))                .Rows.FirstOrDefault()                ?.Get<Document, byte[]>(x => x.Data);        }        public static void RegisterFunction(string group, string name, FncType function, params string[] parameters) =>            Functions.Add(new CoreExpressionFunction(group, name, function, parameters.ToList()));        #endregion    }    public class CoreExpression<TModel, TReturn> : CoreExpression        where TModel : IExpressionModel<TReturn>    {        protected override Type? ReturnType => typeof(TReturn);        public CoreExpression(string expressionString): base(expressionString) { }        [return: MaybeNull]        public new TReturn Evaluate(Dictionary<string, object?>? variables)        {            var result = base.Evaluate(variables);            if(result is TReturn ret)            {                return ret;            }            return default;        }        [return: MaybeNull]        public TReturn Evaluate(TModel model)        {            var values = new Dictionary<string, object?>();            foreach(var variable in ReferencedVariables)            {                values[variable] = CoreUtils.GetPropertyValue(model, variable);            }            var result = base.Evaluate(values);            if(result is TReturn ret)            {                return ret;            }            return default;        }    }}
 |