protected override void GenerateJoin(ParameterDependant dependant, ref CharWriteBuffer sb) { foreach (var child in dependant.Dependants.Values) { if (child.ModelDetail.IdentityProperties.Count != 1) { throw new NotSupportedException($"Relational queries support only one identity on {child.ModelDetail.Type.GetNiceName()}"); } var dependantIdentity = child.ModelDetail.IdentityProperties[0]; sb.Write("JOIN`"); sb.Write(child.ModelDetail.DataSourceEntityName); sb.Write("`ON`"); sb.Write(dependant.ModelDetail.DataSourceEntityName); sb.Write("`.`"); sb.Write(child.ParentMember?.ForeignIdentity); sb.Write("`=`"); sb.Write(child.ModelDetail.DataSourceEntityName); sb.Write("`.`"); sb.Write(dependantIdentity.PropertySourceName); sb.Write('`'); AppendLineBreak(ref sb); GenerateJoin(child, ref sb); } }
protected void Convert(ref CharWriteBuffer sb, QueryOperation select, Expression where, QueryOrder order, int?skip, int?take, Graph graph, ModelDetail modelDetail, MemberContext operationContext) { var hasWhere = where != null; var hasOrderSkipTake = (select == QueryOperation.Many || select == QueryOperation.First) && (order?.OrderExpressions.Length > 0 || skip > 0 || take > 0); GenerateSelect(select, graph, modelDetail, ref sb); GenerateFrom(modelDetail, ref sb); if (hasWhere || hasOrderSkipTake) { var rootDependant = new ParameterDependant(modelDetail, null); var sbWhereOrder = new CharWriteBuffer(); try { if (hasWhere) { GenerateWhere(where, ref sbWhereOrder, rootDependant, operationContext); } if (hasOrderSkipTake) { GenerateOrderSkipTake(order, skip, take, ref sbWhereOrder, rootDependant, operationContext); } GenerateJoin(rootDependant, ref sb); sb.Write(sbWhereOrder); } finally { sbWhereOrder.Dispose(); } } GenerateEnding(select, graph, modelDetail, ref sb); }
protected override void GenerateOrderSkipTake(QueryOrder order, int?skip, int?take, ref CharWriteBuffer sb, ParameterDependant rootDependant, MemberContext operationContext) { if (order?.OrderExpressions.Length > 0) { sb.Write("ORDER BY"); var hasOrder = false; foreach (var orderExp in order.OrderExpressions) { var context = new BuilderContext(rootDependant, operationContext); if (hasOrder) { sb.Write(','); } else { hasOrder = true; } ConvertToSql(orderExp.Expression, ref sb, context); if (orderExp.Descending) { sb.Write("DESC"); } } AppendLineBreak(ref sb); } else if (skip.HasValue || take.HasValue) { sb.Write("ORDER BY CURRENT_TIMESTAMP"); AppendLineBreak(ref sb); } if (skip.HasValue || take.HasValue) { sb.Write("OFFSET "); sb.Write(skip ?? 0); sb.Write(" ROWS"); AppendLineBreak(ref sb); if (take.HasValue) { sb.Write("FETCH NEXT "); sb.Write(take.Value); sb.Write(" ROWS ONLY"); AppendLineBreak(ref sb); } } }
protected override void GenerateWhere(Expression where, ref CharWriteBuffer sb, ParameterDependant rootDependant, MemberContext operationContext) { if (where == null) { return; } sb.Write("WHERE"); var context = new BuilderContext(rootDependant, operationContext); ConvertToSql(where, ref sb, context); AppendLineBreak(ref sb); }
protected override void ConvertToSqlParameterModel(ModelDetail modelDetail, ref CharWriteBuffer sb, BuilderContext context, bool parameterInContext) { var member = context.MemberContext.MemberAccessStack.Pop(); var modelProperty = modelDetail.GetProperty(member.Member.Name); if (modelProperty.IsDataSourceEntity && context.MemberContext.MemberAccessStack.Count > 0) { var subModelInfo = ModelAnalyzer.GetModel(modelProperty.InnerType); context.MemberContext.ModelStack.Push(subModelInfo); if (parameterInContext) { var parentDependant = context.MemberContext.DependantStack.Peek(); if (!parentDependant.Dependants.TryGetValue(subModelInfo.Type, out ParameterDependant dependant)) { dependant = new ParameterDependant(subModelInfo, modelProperty); parentDependant.Dependants.Add(subModelInfo.Type, dependant); } context.MemberContext.DependantStack.Push(dependant); } ConvertToSqlParameterModel(subModelInfo, ref sb, context, parameterInContext); if (parameterInContext) { context.MemberContext.DependantStack.Pop(); } context.MemberContext.ModelStack.Pop(); } else if (context.MemberContext.InCallNoRender > 0) { } else if (context.MemberContext.InCallRenderIdentity > 0) { if (modelDetail.IdentityProperties.Count != 1) { throw new NotSupportedException($"Relational queries support only one identity on {modelDetail.Type.GetNiceName()}"); } var modelIdentity = modelDetail.IdentityProperties[0]; sb.Write('`'); sb.Write(modelDetail.DataSourceEntityName); sb.Write("`.`"); sb.Write(modelIdentity.PropertySourceName); sb.Write("`"); } else { bool closeBrace = false; if (context.MemberContext.MemberAccessStack.Count > 0) { bool memberPropertyHandled = false; var memberProperty = context.MemberContext.MemberAccessStack.Pop(); if (member.Type.Name == typeof(Nullable <>).Name && memberProperty.Member.Name == "Value") { memberPropertyHandled = true; } else if (member.Type == typeof(DateTime)) { memberPropertyHandled = true; closeBrace = true; switch (memberProperty.Member.Name) { case "Year": sb.Write("YEAR("); break; case "Month": sb.Write("MONTH("); break; case "Day": sb.Write("DAY(day,"); break; case "Hour": sb.Write("HOUR("); break; case "Minute": sb.Write("MINUTE("); break; case "Second": sb.Write("SECOND("); break; case "Millisecond": sb.Write("1/1000*MICROSECOND("); break; case "DayOfYear": sb.Write("DAYOFYEAR("); break; case "DayOfWeek": sb.Write("WEEKDAY("); break; default: memberPropertyHandled = false; break; } } if (!memberPropertyHandled) { throw new NotSupportedException($"{member.Member.Name}.{memberProperty.Member.Name} not supported"); } context.MemberContext.MemberAccessStack.Push(memberProperty); } sb.Write('`'); sb.Write(modelDetail.DataSourceEntityName); sb.Write('`'); sb.Write('.'); sb.Write('`'); sb.Write(modelProperty.PropertySourceName); sb.Write('`'); var lastOperator = context.MemberContext.OperatorStack.Peek(); if (lastOperator == Operator.And || lastOperator == Operator.Or) { if (modelProperty.InnerType == typeof(bool)) { sb.Write("=1"); } else { sb.Write("IS NOT NULL"); } } if (closeBrace) { sb.Write(')'); } } context.MemberContext.MemberAccessStack.Push(member); }
public BuilderContext(ParameterDependant rootDependant, MemberContext memberContext) { this.RootDependant = rootDependant; this.MemberContext = memberContext; this.InvertStack = 0; }