BaseQueryTranslateService.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Vit.Linq.ExpressionTree.ComponentModel;
  5. using Vit.Linq.ExpressionTree.CollectionsQuery;
  6. using Vit.Orm.Sql.DataReader;
  7. namespace Vit.Orm.Sql.SqlTranslate
  8. {
  9. public abstract class BaseQueryTranslateService : IQueryTranslateService
  10. {
  11. public SqlTranslateService sqlTranslator { get; protected set; }
  12. public BaseQueryTranslateService(SqlTranslateService sqlTranslator)
  13. {
  14. this.sqlTranslator = sqlTranslator;
  15. }
  16. public virtual string BuildQuery(QueryTranslateArgument arg, CombinedStream stream)
  17. {
  18. string sql = "";
  19. // #0 select
  20. sql += ReadSelect(arg, stream);
  21. #region #1 from
  22. sql += "\r\n from " + ReadInnerTable(arg, stream.source);
  23. #endregion
  24. #region #2 join
  25. if (stream.joins != null)
  26. {
  27. sql += ReadJoin(arg,stream);
  28. }
  29. #endregion
  30. // #3 where 1=1
  31. if (stream.where != null)
  32. {
  33. var where = sqlTranslator.EvalExpression(arg, stream.where);
  34. if (!string.IsNullOrWhiteSpace(where)) sql += "\r\n where " + where;
  35. }
  36. #region #4 group by
  37. if (stream.groupByFields != null)
  38. {
  39. sql += "\r\n group by " + ReadGroupBy(arg, stream);
  40. }
  41. #endregion
  42. #region #5 having
  43. if (stream.having != null)
  44. {
  45. var where = sqlTranslator.EvalExpression(arg, stream.having);
  46. if (!string.IsNullOrWhiteSpace(where)) sql += "\r\n having " + where;
  47. }
  48. #endregion
  49. // #6 OrderBy
  50. if (stream.orders?.Any() == true)
  51. {
  52. sql += "\r\n order by " + ReadOrderBy(arg, stream);
  53. }
  54. // #7 Range, limit 1000,10 limit {skip},{take} | limit {take}
  55. if (stream.take != null || stream.skip != null)
  56. {
  57. string sqlRange = "limit " + (stream.skip == null ? "" : (stream.skip + ",")) + (stream.take ?? 100000000);
  58. sql += "\r\n " + sqlRange;
  59. }
  60. return sql;
  61. }
  62. #region Read partial query
  63. /// <summary>
  64. /// "select *";
  65. /// </summary>
  66. /// <param name="stream"></param>
  67. /// <returns></returns>
  68. protected virtual string ReadSelect(QueryTranslateArgument arg, CombinedStream stream, string prefix = "select")
  69. {
  70. return prefix + " *";
  71. }
  72. protected virtual string ReadJoin(QueryTranslateArgument arg, CombinedStream stream)
  73. {
  74. var sql = "";
  75. stream.joins?.ForEach(streamToJoin =>
  76. {
  77. sql += "\r\n " + (streamToJoin.joinType == EJoinType.InnerJoin ? "inner join" : "left join");
  78. sql += " " + ReadInnerTable(arg, streamToJoin.right);
  79. var on = sqlTranslator.EvalExpression(arg, streamToJoin.on);
  80. if (!string.IsNullOrWhiteSpace(on)) sql += " on " + on;
  81. });
  82. return sql;
  83. }
  84. protected virtual string ReadGroupBy(QueryTranslateArgument arg, CombinedStream stream)
  85. {
  86. var node = stream.groupByFields;
  87. List<string> fields = new();
  88. if (node?.nodeType == NodeType.New)
  89. {
  90. ExpressionNode_New newNode = node;
  91. newNode.constructorArgs.ForEach((Action<MemberBind>)(nodeArg =>
  92. {
  93. fields.Add(sqlTranslator.EvalExpression(arg, (ExpressionNode)nodeArg.value));
  94. }));
  95. }
  96. else if (node?.nodeType == NodeType.Member)
  97. {
  98. fields.Add(sqlTranslator.EvalExpression(arg, node));
  99. }
  100. else
  101. {
  102. throw new NotSupportedException("[QueryTranslator] groupByFields is not valid: must be New or Member");
  103. }
  104. return String.Join(", ", fields);
  105. }
  106. protected virtual string ReadOrderBy(QueryTranslateArgument arg, CombinedStream stream)
  107. {
  108. var fields = stream.orders.Select(field =>
  109. {
  110. var sqlField = sqlTranslator.EvalExpression(arg, field.member);
  111. return sqlField + " " + (field.asc ? "asc" : "desc");
  112. }
  113. ).ToList();
  114. return String.Join(", ", fields);
  115. }
  116. #endregion
  117. protected string ReadInnerTable(QueryTranslateArgument arg, IStream stream)
  118. {
  119. if (stream is SourceStream sourceStream)
  120. {
  121. IQueryable query = sourceStream.GetSource() as IQueryable;
  122. var tableName = arg.dbContext.GetEntityDescriptor(query.ElementType)?.tableName;
  123. return $"{sqlTranslator.DelimitIdentifier(tableName)} as " + stream.alias;
  124. }
  125. if (stream is CombinedStream baseStream)
  126. {
  127. var innerQuery = BuildQuery(arg, baseStream);
  128. return $"({innerQuery}) as " + stream.alias;
  129. }
  130. throw new NotSupportedException();
  131. }
  132. protected virtual string BuildReader(QueryTranslateArgument arg, CombinedStream stream, EntityReader reader)
  133. {
  134. var resultEntityType = arg.resultEntityType;
  135. ExpressionNode selectedFields = stream.select?.fields as ExpressionNode;
  136. if (selectedFields == null)
  137. {
  138. if (stream.joins?.Any() != true && resultEntityType != null)
  139. {
  140. selectedFields = ExpressionNode.Member(parameterName: stream.source.alias, memberName: null).Member_SetType(resultEntityType);
  141. }
  142. }
  143. if (selectedFields == null)
  144. throw new NotSupportedException("select could not be null");
  145. if (resultEntityType == null && selectedFields.nodeType == NodeType.New)
  146. {
  147. resultEntityType = selectedFields.New_GetType();
  148. }
  149. //if (resultEntityType == null)
  150. // throw new NotSupportedException("resultEntityType could not be null");
  151. var sqlFields = reader.BuildSelect(arg, resultEntityType, sqlTranslator, arg.dbContext.convertService, selectedFields);
  152. if (arg.dataReader == null) arg.dataReader = reader;
  153. return (stream.distinct == true ? "distinct " : "") + sqlFields;
  154. }
  155. protected virtual void ReverseOrder(QueryTranslateArgument arg, CombinedStream stream)
  156. {
  157. stream.orders ??= new();
  158. var orders = stream.orders;
  159. // make sure orders exist
  160. if (!orders.Any())
  161. {
  162. AddOrder(stream.source);
  163. stream.joins?.ForEach(right => AddOrder(right.right));
  164. #region AddOrder
  165. void AddOrder(IStream source)
  166. {
  167. if (source is SourceStream sourceStream)
  168. {
  169. var entityType = sourceStream.GetEntityType();
  170. var entityDescriptor = arg.dbContext.GetEntityDescriptor(entityType);
  171. if (entityDescriptor != null)
  172. {
  173. var member = ExpressionNode_RenameableMember.Member(stream: source, entityType);
  174. member.memberName = entityDescriptor.keyName;
  175. orders.Add(new OrderField { member = member, asc = true });
  176. }
  177. }
  178. }
  179. #endregion
  180. }
  181. // reverse order
  182. orders?.ForEach(order => order.asc = !order.asc);
  183. }
  184. }
  185. }