using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Drawing.Drawing2D; using NPOI.OpenXmlFormats.Dml.Diagram; using SqlSugar; using Tnb.Core; using Tnb.Vengine.DataAccess; namespace Tnb.Vengine.Domain; internal class VmQueryParser { public const string MAIN_ALIES = "m"; public const char NAVI_SEPERATE = '.'; public const char PROP_SEPERATE = '&'; private readonly IDataAccess _dataAccess; private readonly Vmodel _root; private readonly VmQueryInput _input; public Dictionary Navigates { get; } = new Dictionary(); public VmQueryParser(IDataAccess dataAccess, Vmodel rootModel, VmQueryInput input) { _dataAccess = dataAccess; _root = rootModel; _input = input; } /// /// 解析查询参数 /// public void ParseQueryInput() { // 初始化根模型 Navigates.Clear(); VmNavigate main = new(MAIN_ALIES); main.navConfig.naviModel = _root; Navigates.Add(MAIN_ALIES, main); ParseOutputStr(_input.o); ParseQueryPara(_input.q); ParseSortPara(_input.sort); } /// /// 清除字符串特殊符号 /// private string ClearStr(string str) { return str.Trim(' ', '\r', '\n', '\t'); } /// /// 解析输出属性字符串 /// private void ParseOutputStr(string output) { // t1.t2.id List outputs = output.Split(',').Distinct().ToList(); foreach (string? s in outputs) { var outStr = ClearStr(s); if (string.IsNullOrWhiteSpace(outStr)) { continue; } // t1 t2 id string[] codes = outStr.Split(NAVI_SEPERATE); // 根据导航路径添加选择器 string vmPath = MAIN_ALIES; for (int i = 0; i < codes.Length - 1; i++) { string code = ClearStr(codes[i]); vmPath = i == 0 ? code : vmPath + NAVI_SEPERATE + code; if (!Navigates.ContainsKey(vmPath)) { Navigates.Add(vmPath, new VmNavigate(vmPath)); } } // 添加返回的属性到选择器 string lastCode = ClearStr(codes[^1]); Navigates[vmPath].selects.Add(new VmSelectProp(lastCode)); } } /// /// 解析查询参数 /// private void ParseQueryPara(DObject? query) { if (query == null) { return; } foreach (KeyValuePair item in query) { string[] codes = item.Key.Split(NAVI_SEPERATE); // 将导航属性查询条件添加到选择器 string vmPath = MAIN_ALIES; for (int i = 0; i < codes.Length - 1; i++) { string code = ClearStr(codes[i]); vmPath = i == 0 ? code : vmPath + NAVI_SEPERATE + code; if (!Navigates.ContainsKey(vmPath)) { Navigates.Add(vmPath, new VmNavigate(vmPath)); } } // 添加返回的属性到选择器 string lastCode = ClearStr(codes[^1]); Navigates[vmPath].wheres.Add(new VmWhereProp(lastCode) { value = item.Value }); } } /// /// 解析排序参数 /// private void ParseSortPara(string? sort) { if (string.IsNullOrWhiteSpace(sort)) { return; } string[] orders = sort.Split(','); foreach (string s in orders) { var orderStr = ClearStr(s); if (string.IsNullOrWhiteSpace(orderStr)) { continue; } // 拆分 m.code desc string[] codes = orderStr.Split(' ', 2); // 拆分 m.code (string?, string) orderPath = codes[0].GetParent(NAVI_SEPERATE); orderPath.Item1 ??= MAIN_ALIES; ThrowIf.When(!Navigates.ContainsKey(orderPath.Item1), $"排序参数{orderStr}错误,导航路径{orderPath.Item1}必须包含在输出参数中"); VmOrderProp orderby = new(orderPath.Item2); if (codes.Length == 2) { OrderByType? orderType = codes[1].ToLower() switch { "asc" => OrderByType.Asc, "desc" => OrderByType.Desc, _ => null }; ThrowIf.IsNull(orderType, $"排序方式{orderStr}不正确"); orderby.orderType = orderType.Value; } Navigates[orderPath.Item1].orders.Add(orderby); } } /// /// 加载单个导航属性模型 /// private async Task LoadVmNavigateModelAsync(VmNavigate nav, Dictionary navs) { if (nav.navConfig.naviModel != null) { return nav.navConfig.naviModel; } // 分割导航路径, a.b.c -> a.b, c (string?, string) path = nav.path.GetParent(NAVI_SEPERATE); path.Item1 ??= MAIN_ALIES; nav.parent = Navigates[path.Item1]; Vmodel parentVm = await LoadVmNavigateModelAsync(nav.parent, navs); // 获取导航属性配置 nav.navConfig = parentVm.navProps.FirstOrDefault(a => a.code == path.Item2)!; ThrowIf.IsNull(nav.navConfig, $"模型({parentVm.fullCode})的导航属性{nav.path}配置错误: 找不到(code = {path.Item2})的导航属性"); // 获取导航模型 nav.navConfig.naviModel = await _dataAccess.GetVmodelAsync(nav.navConfig.vmid); ThrowIf.IsNull(nav.navConfig.naviModel, $"模型({parentVm.fullCode})的导航属性{nav.path}配置错误: 找不到(id = {nav.navConfig.vmid})的模型"); // 处理导航模型 if (nav.navConfig.refCode == MAIN_ALIES) { var field = nav.parent.navConfig.naviModel!.PropToFieldCode(nav.navConfig.refProp); ThrowIf.IsNull(field, $"模型({parentVm.fullCode})的导航属性{nav.path}配置错误: 找不到(code = {nav.navConfig.refProp})的字段"); field = nav.navConfig.naviModel.PropToFieldCode(nav.navConfig.fkProp); ThrowIf.IsNull(field, $"模型({parentVm.fullCode})的导航属性{nav.path}配置错误: 在子模型{nav.navConfig.naviModel.fullCode}中找不到(code = {nav.navConfig.fkProp})的字段"); if (!nav.parent.selects.Any(a => a.code == nav.navConfig.refProp)) { nav.parent.selects.Add(new VmSelectProp(nav.navConfig.refProp)); } if (!nav.selects.Any(a => a.code == nav.navConfig.fkProp)) { nav.selects.Add(new VmSelectProp(nav.navConfig.fkProp)); } } else { var navPath = nav.path + NAVI_SEPERATE + nav.navConfig.refCode; if (!Navigates.ContainsKey(navPath)) { VmNavigate midNav = new VmNavigate(navPath); midNav.navConfig = parentVm.navProps.FirstOrDefault(a => a.code == nav.navConfig.refCode)!; ThrowIf.IsNull(midNav.navConfig, $"模型({parentVm.fullCode})的导航属性{midNav.path}配置错误: 找不到(code = {nav.navConfig.refCode})的导航属性"); midNav.navConfig.naviModel = await _dataAccess.GetVmodelAsync(midNav.navConfig.vmid); ThrowIf.IsNull(midNav.navConfig.naviModel, $"模型({parentVm.fullCode})的导航属性{midNav.path}配置错误: 找不到(id = {midNav.navConfig.vmid})的模型"); } } return nav.navConfig.naviModel; } /// /// 加载单个导航属性模型 /// public async Task LoadNavigateAsync() { Dictionary tobeAdd = new Dictionary(); foreach (VmNavigate nav in Navigates.Values) { _ = await LoadVmNavigateModelAsync(nav, tobeAdd); } foreach (var item in tobeAdd) { Navigates.Add(item.Key, item.Value); } foreach (VmNavigate nav in Navigates.Values) { nav.HandleStar(); nav.LoadDbProp(); } } /// /// 处理一对一联表关系,生成联表信息 /// /// /// SELECT * FROM wms_distask_h m INNER JOIN eqp_equipment equip ON m.device_id=equip."id" INNER JOIN eqp_equip_type equipType ON equip.equip_type_id=equipType."id" /// public List GetJoinInfos() { List joins = new(); // 主查询中只处理主表和一对一的联表 IEnumerable navs = Navigates.Values.Where(a => a.path != MAIN_ALIES && a.navConfig.navType == eNavigateType.OneToOne); foreach (VmNavigate? nav in navs) { Debug.Assert(nav.parent != null && nav.navConfig.naviModel != null); JoinInfoParameter join = new() { TableName = nav.navConfig.naviModel.tableName, ShortName = nav.pathCode, Type = JoinType.Left }; var refNav = nav.navConfig.refCode == MAIN_ALIES ? nav.parent : Navigates[nav.path + "." + nav.navConfig.refCode]; var fkField = nav.navConfig.naviModel.PropToFieldCode(nav.navConfig.fkProp); var refField = refNav.navConfig.naviModel!.PropToFieldCode(nav.navConfig.refProp); join.Models = ObjectFuncModel.Create("Equals", $"{nav.pathCode}.{fkField}", $"{refNav.pathCode}.{refField}"); joins.Add(join); } return joins; } /// /// 生成查询过滤条件 /// /// /// public List GetConditionalModels() { List wheres = new(); foreach (VmNavigate? nav in Navigates.Values.Where(a => (a.path == MAIN_ALIES || a.navConfig.navType == eNavigateType.OneToOne) && a.wheres.Count > 0)) { foreach (VmWhereProp where in nav.wheres) { if (where.value is IEnumerable arrObj) { object[] val = arrObj.ToArray(); string op = val[0].ToString()!; switch (op) { case "><": wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThan, CSharpTypeName = where.csType }); wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThan, CSharpTypeName = where.csType }); break; case ">=<": wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThanOrEqual, CSharpTypeName = where.csType }); wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThan, CSharpTypeName = where.csType }); break; case "><=": wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThan, CSharpTypeName = where.csType }); wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThanOrEqual, CSharpTypeName = where.csType }); break; case ">=<=": wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThanOrEqual, CSharpTypeName = where.csType }); wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThanOrEqual, CSharpTypeName = where.csType }); break; case "in": wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = string.Join(',', val.Skip(1)), ConditionalType = ConditionalType.In, CSharpTypeName = where.csType }); break; default: op = string.Empty; break; } } else { ConditionalType conditionalType = ConditionalType.Equal; string? value = where.value?.ToString(); if (string.IsNullOrEmpty(value)) { continue; } if (value.Length >= 2) { string op = value[..2]; switch (op) { case "%%": conditionalType = ConditionalType.Like; break; case ">>": conditionalType = ConditionalType.GreaterThan; break; case "<<": conditionalType = ConditionalType.LessThan; break; case ">=": conditionalType = ConditionalType.GreaterThanOrEqual; break; case "<=": conditionalType = ConditionalType.LessThanOrEqual; break; case "==": conditionalType = ConditionalType.Equal; break; default: op = string.Empty; break; } if (!string.IsNullOrEmpty(op)) { value = value.RemovePreFix(op); if (value.ToLower() == "null") { value = null; } } } wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = value, ConditionalType = conditionalType, CSharpTypeName = where.csType }); } } } return wheres; } /// /// 生成按关键字查询的条件列表 /// /// 是否钻取子表关键词查询 /// public ConditionalCollections GetKeywordConditional(bool drill = true) { ConditionalCollections conditionals = new() { ConditionalList = new List>() }; if (string.IsNullOrWhiteSpace(_input.k)) { return conditionals; } WhereType wType = WhereType.And; IEnumerable navs = Navigates.Values.WhereIF(!drill, a => a.path == MAIN_ALIES).Where(a => a.navConfig.navType != eNavigateType.OneToMany); foreach (VmNavigate? nav in navs) { foreach (VmSelectProp? prop in nav.selects.Where(a => a.fuzzy)) { conditionals.ConditionalList.Add(new(wType, new ConditionalModel() { FieldName = prop.fieldName, ConditionalType = ConditionalType.Like, FieldValue = _input.k, CSharpTypeName = prop.csType })); wType = WhereType.Or; } } return conditionals; } /// /// 生成排序条件列表 /// /// public List GetOrderByModels() { IEnumerable navs = Navigates.Values.Where(a => a.orders.Count > 0); return navs.SelectMany(a => { return a.orders.Select(b => new OrderByModel { FieldName = b.fieldName, OrderByType = b.orderType }); }).ToList(); } /// /// 生成查询字段列表 /// /// /// public List GetSelectModels() { IEnumerable navs = Navigates.Values.Where(a => (a.path == MAIN_ALIES || a.navConfig.navType == eNavigateType.OneToOne) && a.selects.Count > 0); return navs.SelectMany(a => { return a.selects.Select(b => new SelectModel { FiledName = b.fieldName, AsName = (a.path == MAIN_ALIES ? "" : a.pathCode + PROP_SEPERATE) + b.code }); }).ToList(); } } internal class VmNavigate { public VmNavigate? parent { get; set; } public VmNavProp navConfig { get; set; } = new VmNavProp(); public string path { get; set; } public string pathCode { get; set; } public List selects { get; set; } = new List(); public List wheres { get; set; } = new List(); public List orders { get; set; } = new List(); public VmNavigate(string vmPath) { path = vmPath; pathCode = vmPath.Replace(VmQueryParser.NAVI_SEPERATE, VmQueryParser.PROP_SEPERATE); } /// /// 处理占位符星号 /// public void HandleStar() { if (selects.Any(a => a.code == "*")) { selects.Clear(); navConfig.naviModel!.dbProps.ForEach(a => { selects.Add(new VmSelectProp(a.code)); }); } } /// /// 将属性名转换为字段名 /// public void LoadDbProp() { foreach (VmSelectProp item in selects) { VmDbProp? prop = navConfig.naviModel!.GetDbProp(item.code); ThrowIf.IsNull(prop, $"输出参数{path}.{item.code}错误: 在模型{navConfig.naviModel.fullCode}中找不到属性({item.code})对应的字段"); item.field = prop.field; item.fieldName = pathCode + "." + item.field; item.fuzzy = prop.fuzzy; item.csType = prop.csType; item.asName = (path == VmQueryParser.MAIN_ALIES ? "" : pathCode + VmQueryParser.PROP_SEPERATE) + item.code; } foreach (VmOrderProp item in orders) { VmDbProp? prop = navConfig.naviModel!.GetDbProp(item.code); ThrowIf.IsNull(prop, $"排序参数{path}.{item.code}错误: 在模型{navConfig.naviModel.fullCode}中找不到属性({item.code})对应的字段"); item.field = prop.field; item.fieldName = pathCode + "." + item.field; } foreach (VmWhereProp item in wheres) { VmDbProp? prop = navConfig.naviModel!.GetDbProp(item.code); ThrowIf.IsNull(prop, $"查询参数{path}.{item.code}错误: 在模型{navConfig.naviModel.fullCode}中找不到属性({item.code})对应的字段"); item.field = prop.field; item.fieldName = pathCode + "." + item.field; item.csType = prop.csType; } //props.RemoveAll(a => string.IsNullOrEmpty(a.field)); } } internal class VmQueryBaseProp { public string code { get; set; } public string field { get; set; } = string.Empty; public string fieldName { get; set; } = string.Empty; public VmQueryBaseProp(string code) { this.code = code; } } internal class VmSelectProp : VmQueryBaseProp { public string asName { get; set; } = string.Empty; public string csType { get; set; } = "string"; public bool fuzzy { get; set; } public VmSelectProp(string code) : base(code) { } } internal class VmOrderProp : VmQueryBaseProp { public OrderByType orderType { get; set; } = OrderByType.Asc; public VmOrderProp(string code) : base(code) { } } internal class VmWhereProp : VmQueryBaseProp { public string csType { get; set; } = "string"; [AllowNull] public object value { get; set; } public VmWhereProp(string code) : base(code) { } }