public static (IEnumerable <StringBasedMappedProperty> property, IEnumerable <MappedTable> tables) BuildMap( BuildMapState state, MethodCallExpression caseExpression, MapType nextMap, string toPrefix = null) { var(isElse, elseResult) = IsElse(caseExpression); if (!isElse) { throw new InvalidOperationException("The method only handles sql case statements"); } var(@else, tables) = ComplexMapBuilder.BuildMap(state, elseResult); var el = @else.ToArray(); if (el.Length != 1) { throw new SqlBuilderException(state.MappingPurpose, caseExpression.Arguments[0]); } var(cases, tables2) = GetDslCases(state, caseExpression.Object); return(CompileCases( state, cases, el[0], tables.Concat(tables2), caseExpression.Type, toPrefix)); }
static (IEnumerable <(StringBasedMappedProperty when, StringBasedMappedProperty then)> cases, StringBasedMappedProperty @else, IEnumerable <MappedTable> tables) GetCasesX( BuildMapState state, Expression expr) { var caseExpression = expr as ConditionalExpression; if (caseExpression == null) { var(elseP, elseTables) = ComplexMapBuilder.BuildMap( state, ReflectionUtils.RemoveConvert(expr)); var elseProperties = elseP.ToArray(); if (elseProperties.Length != 1) { throw new SqlBuilderException(state.MappingPurpose, caseExpression); } return(CodingConstants.Empty.Case, elseProperties[0], elseTables); } var(ifP, ifTables) = ComplexMapBuilder.BuildMap( state, ReflectionUtils.RemoveConvert(caseExpression.Test)); var ifProperties = ifP.ToArray(); if (ifProperties.Length != 1) { throw new SqlBuilderException(state.MappingPurpose, caseExpression); } var(thenP, thenTables) = ComplexMapBuilder.BuildMap( state, ReflectionUtils.RemoveConvert(caseExpression.IfTrue)); var thenProperties = thenP.ToArray(); if (thenProperties.Length != 1) { throw new SqlBuilderException(state.MappingPurpose, caseExpression); } var(otherCases, @else, otherTables) = GetCasesX( state, ReflectionUtils.RemoveConvert(caseExpression.IfFalse)); return( otherCases.Prepend((ifProperties[0], thenProperties[0])), @else, ifTables.Concat(thenTables).Concat(otherTables) ); }
static (IEnumerable <(StringBasedMappedProperty when, StringBasedMappedProperty then)> cases, IEnumerable <MappedTable> tables) GetDslCases( BuildMapState state, Expression caseExpression) { if (caseExpression == null) { return(CodingConstants.Empty.Case, CodingConstants.Empty.MappedTable); } var thenObject = caseExpression as MethodCallExpression; if (thenObject == null) { throw new SqlBuilderException(state.MappingPurpose, caseExpression); } var(isThen, thenResult) = IsThen(thenObject); if (!isThen) { throw new SqlBuilderException(state.MappingPurpose, thenObject); } var whenObject = thenObject.Object as MethodCallExpression; if (whenObject == null) { throw new SqlBuilderException(state.MappingPurpose, thenObject.Object); } var(isWhen, whenCondition) = IsWhen(whenObject); if (!isWhen) { throw new SqlBuilderException(state.MappingPurpose, whenObject); } var(whenProperties, whenTables) = ComplexMapBuilder.BuildMap(state, whenCondition); var(thenProperties, thenTables) = ComplexMapBuilder.BuildMap(state, thenResult); var whenP = whenProperties.ToArray(); var thenP = thenProperties.ToArray(); if (whenP.Length != 1 || thenP.Length != 1) { throw new SqlBuilderException(state.MappingPurpose, caseExpression); } var(cases, tables) = GetDslCases(state, whenObject.Object); return( cases.Append((whenP[0], thenP[0])), tables.Concat(whenTables).Concat(thenTables) ); }
public QueryElementBasedMappedProperty Convert(BuildMapState state) { var mappingContext = MappingContext .Select(x => state.WrappedSqlStatement.Tables[x]) .ToArray(); return(new QueryElementBasedMappedProperty( FromParams.Convert(state), To, MappedPropertyType, mappingContext, PropertySegmentConstructors)); }
public static (IEnumerable <StringBasedMappedProperty> property, IEnumerable <MappedTable> tables) BuildMap( BuildMapState state, ConditionalExpression caseExpression, string toPrefix = null) { var(cases, @else, tables) = GetCasesX(state, caseExpression); return(CompileCases( state, cases, @else, tables.Concat(tables), caseExpression.Type, toPrefix)); }
static (IEnumerable <StringBasedMappedProperty> properties, IEnumerable <MappedTable> tables, bool isConstant) BuildMapWithErrorHandling( BuildMapState state, Expression expr, MapType nextMap, string toPrefix = null) { try { return(BuildMap(state, expr, nextMap, toPrefix)); } catch (Exception e) { throw new SqlBuilderException(state.MappingPurpose, expr, e); } }
/// <summary> /// Compile the query into something which can be executed multiple times /// </summary> public static ICompiledQuery <TArgs, TMapped> Compile <TArgs, TResult, TMapped>( ISqlSyntax sqlSyntax, SqlExecutor <TArgs, TResult> query, LambdaExpression mapper, bool requiresPropertyUnwrap, ILogger logger) { var(wrappedBuilder, parameters) = query.ToSqlStatement(); var wrappedStatement = new SqlStatement(wrappedBuilder); var argsParam = mapper.Parameters.Count > 1 ? mapper.Parameters[1] : null; var state = new BuildMapState(query.PrimaryTableMember.memberName, parameters, mapper.Parameters[0], argsParam, wrappedStatement, query.SqlSyntax, true, MappingPurpose.Mapping); var(properties, tables) = MapBuilder.BuildMapFromRoot(state, mapper.Body); properties = properties.Enumerate(); var statement = new MappedSelectStatement(properties, tables, wrappedStatement.Tables.First().PrimaryKey); var builder = new MappedSqlStatementBuilder(state, properties, statement, wrappedBuilder, sqlSyntax); return(builder.Compile <TArgs, TMapped>(statement, parameters.Parameters, sqlSyntax, QueryParseType.ORM, requiresPropertyUnwrap)); }
public static (IEnumerable <StringBasedMappedProperty> property, IEnumerable <MappedTable> tables) BuildMap( BuildMapState state, MethodCallExpression caseExpression, MapType nextMap, string toPrefix = null) { var(isElse, elseResult) = IsElse(caseExpression); if (!isElse) { throw new InvalidOperationException("The method only handles sql case statements"); } var(@else, tables) = ComplexMapBuilder.BuildMap(state, elseResult); var el = @else.ToArray(); if (el.Length != 1) { throw new SqlBuilderException(state.MappingPurpose, caseExpression.Arguments[0]); } var(subject, cases, tables2) = GetCases(state, caseExpression.Object, MapType.Other, toPrefix); var prop = new StringBasedMappedProperty( new SimpleCaseSqlExpression <StringBasedElement>( subject.FromParams, cases.Select(c => (c.when.FromParams, c.then.FromParams)), el[0].FromParams), toPrefix, caseExpression.Type, state.MappingContext.propertyName, cases .SelectMany(x => new [] { x.when, x.then }) .Concat(@else) .SelectMany(c => c.PropertySegmentConstructors) .ToArray()); return( prop.ToEnumerable(), tables.Concat(tables2)); }
static (IEnumerable <StringBasedMappedProperty> property, IEnumerable <MappedTable> tables) CompileCases( BuildMapState state, IEnumerable <(StringBasedMappedProperty when, StringBasedMappedProperty then)> cases,
static (IEnumerable <StringBasedMappedProperty> properties, IEnumerable <MappedTable> tables, bool isConstant) BuildMap( BuildMapState state, Expression expr, MapType nextMap, string toPrefix) { var(isConstant, requiresArgs) = ReflectionUtils.IsConstant(expr, state.ArgsObject); if (isConstant) { var result = requiresArgs ? QueryArgAccessor.Create(state.ArgsObject, expr) : ReflectionUtils.ExecuteExpression(expr); var paramName = state.Parameters.AddParam(result, expr.Type); return( new StringBasedMappedProperty( null, paramName, toPrefix, expr.Type, state.MappingContext.propertyName, aggregatedToTable: state.MappingContext.propertyName).ToEnumerable(), EmptyMappedTables, true ); } switch (expr.NodeType) { case ExpressionType.Convert: return(BuildMapWithErrorHandling(state, (expr as UnaryExpression).Operand, nextMap, toPrefix)); case ExpressionType.Parameter: return( new [] { new StringBasedMappedProperty( expr as ParameterExpression, null, toPrefix, expr.Type, state.MappingContext.propertyName) }, EmptyMappedTables, false ); case ExpressionType.AndAlso: case ExpressionType.OrElse: case ExpressionType.Add: case ExpressionType.Subtract: case ExpressionType.Multiply: case ExpressionType.Divide: case ExpressionType.Equal: case ExpressionType.NotEqual: case ExpressionType.GreaterThan: case ExpressionType.GreaterThanOrEqual: case ExpressionType.LessThan: case ExpressionType.LessThanOrEqual: var asB = expr as BinaryExpression; return(BuildMapForBinaryCondition(state, asB.Left, asB.Right, asB.Type, asB.NodeType, toPrefix).AddT(false)); case ExpressionType.Conditional: var asC = expr as ConditionalExpression; return(CaseMapBuilder.BuildMap(state, asC, toPrefix).AddT(false)); case ExpressionType.MemberAccess: return(BuildMapForMemberAccess(state, expr as MemberExpression, nextMap, toPrefix)); case ExpressionType.New: return(BuildMapForConstructor(state, expr as NewExpression, nextMap, toPrefix: toPrefix).AddT(false)); case ExpressionType.MemberInit: return(BuildMapForMemberInit(state, expr as MemberInitExpression, nextMap, toPrefix).AddT(false)); case ExpressionType.ArrayLength: return(BuildMapForCount(state, (expr as UnaryExpression).Operand, toPrefix).AddT(false)); case ExpressionType.NewArrayInit: case ExpressionType.NewArrayBounds: return(BuildMapForNewArray(state, expr as NewArrayExpression, toPrefix).AddT(false)); case ExpressionType.ListInit: return(BuildMapForNewList(state, expr as ListInitExpression, toPrefix).AddT(false)); case ExpressionType.Call: var exprMethod = expr as MethodCallExpression; var isOrderByRowNumber = ReflectionUtils.IsOrderByRowNumber(exprMethod); if (isOrderByRowNumber) { return(BuildMapForOrderByRowNumber(state, exprMethod, toPrefix).AddT(false)); } var(isIn, inLhs, inRhs) = ReflectionUtils.IsIn(exprMethod); if (isIn) { return(BuildMapForIn(state, inLhs, inRhs, toPrefix).AddT(false)); } var(isCount, countExpr) = ReflectionUtils.IsCount(expr); if (isCount) { return(BuildMapForCount(state, countExpr, toPrefix).AddT(false)); } var(isSum, sumExpr, sumMapper) = ReflectionUtils.IsSum(exprMethod); if (isSum) { return(sumMapper == null ? BuildMapForSum(state, sumExpr, toPrefix).AddT(false) : BuildMapForSum(state, sumExpr, sumMapper, toPrefix).AddT(false)); } var(isAverage, averageExpr, averageMapper) = ReflectionUtils.IsAverage(exprMethod); if (isAverage) { return(averageMapper == null ? BuildMapForAverage(state, averageExpr, toPrefix).AddT(false) : BuildMapForAverage(state, averageExpr, averageMapper, toPrefix).AddT(false)); } var(isMax, maxExpr, maxMapper) = ReflectionUtils.IsMax(exprMethod); if (isMax) { return(maxMapper == null ? BuildMapForMax(state, maxExpr, toPrefix).AddT(false) : BuildMapForMax(state, maxExpr, maxMapper, toPrefix).AddT(false)); } var(isMin, minExpr, minMapper) = ReflectionUtils.IsMin(exprMethod); if (isMin) { return(minMapper == null ? BuildMapForMin(state, minExpr, toPrefix).AddT(false) : BuildMapForMin(state, minExpr, minMapper, toPrefix).AddT(false)); } var oneExpr = ReflectionUtils.IsOne(exprMethod); if (oneExpr != null) { return(BuildMapForOne(state, oneExpr, nextMap, toPrefix)); } var(isToList, enumerableL) = ReflectionUtils.IsToList(exprMethod); if (isToList) { // .ToList(...) is invisible as far as nextMap is concerned return(BuildMapWithErrorHandling(state, enumerableL, nextMap, toPrefix)); } var(isToArray, enumerableA) = ReflectionUtils.IsToArray(exprMethod); if (isToArray) { // .ToArray(...) is invisible as far as nextMap is concerned return(BuildMapWithErrorHandling(state, enumerableA, nextMap, toPrefix)); } var(isSelect, enumerableS, mapper) = ReflectionUtils.IsSelectWithLambdaExpression(exprMethod); if (isSelect) { return(BuildMapForSelect(state, enumerableS, nextMap, mapper, toPrefix).AddT(false)); } var isCase = CaseMapBuilder.IsCase(exprMethod); if (isCase) { return(CaseMapBuilder.BuildMap(state, exprMethod, nextMap, toPrefix).AddT(false)); } var isSimpleCase = SimpleCaseMapBuilder.IsCase(exprMethod); if (isSimpleCase) { return(SimpleCaseMapBuilder.BuildMap(state, exprMethod, nextMap, toPrefix).AddT(false)); } break; default: break; } throw BuildMappingError(state.MappingPurpose, expr); }
static (IEnumerable <StringBasedMappedProperty> properties, IEnumerable <MappedTable> tables) BuildMapForBinaryCondition(BuildMapState state, Expression left, Expression right, Type combinedType, ExpressionType combiner, string toPrefix = null) =>
static (IEnumerable <StringBasedMappedProperty> properties, IEnumerable <MappedTable> tables) BuildMapForConstructor(BuildMapState state, NewExpression expr, MapType nextMap, string toPrefix = null) { // TODO: relax this condition // The issue is within ObjectPropertyGraphBuilder, complex properties (or constructor args) // are defined by the inner simple properties. e.g. property name = OuterObj.InnerProp will create // an outer obj and an inner prop. But if inner prop is not set, then there is no reference to outer // obj either. // see also supporting tests: // PropertyGraph_ReturnsMultipleComplexArgsWithNoSimpleProps_ReturnsCorrectOPG1 // PropertyGraph_ReturnsMultipleComplexArgsWithNoSimpleProps_ReturnsCorrectOPG2 // ReturnMultipleFromMap_PreMappedWithComplexProperty // ReturnMultipleFromMap_PreMappedWithSimpleConstructorArg // ReturnMultipleFromMap_PreMappedWithSimplePropertyAndSimpleConstructorArg // SimpleMapReturningEmptyObject if (nextMap != MapType.MemberInit && expr.Arguments.Count == 0) { throw BuildMappingError(state.MappingPurpose, $"You cannot map to an object with has no data from table columns: {expr}."); } return(expr.Arguments .Select((ex, i) => (type: ex.Type, map: BuildMapWithErrorHandling(state, ex, MapType.Other, toPrefix: CombineStrings(toPrefix, SqlStatementConstants.ConstructorArgs.BuildConstructorArg(i))))) .Select((map, i) => ( map.Item2.properties.SelectMany(p => CreateContructorArg(p, map.type, i)), map.map.tables.Select(x => new MappedTable(x.From, CombineStrings(SqlStatementConstants.ConstructorArgs.BuildConstructorArg(i), x.To), x.TableresultsAreAggregated)))) .AggregateTuple2()); IEnumerable <StringBasedMappedProperty> CreateContructorArg(StringBasedMappedProperty arg, Type argType, int argIndex) { var many = PropertyRepresentsTable(state, arg) ? SplitMapOfComplexProperty(state, arg, argType) : arg.ToEnumerable(); return(many.Select(q => q.With( constructorArgs: q.PropertySegmentConstructors.Prepend(expr.Constructor).ToArray()))); } }
public static (IEnumerable <StringBasedMappedProperty> properties, IEnumerable <MappedTable> tables) BuildMap(BuildMapState state, Expression expr) { var(x, y, _) = BuildMapWithErrorHandling(state, expr, MapType.Root); return(x, y); }
public static (IEnumerable <QueryElementBasedMappedProperty> properties, IEnumerable <StrongMappedTable> tables) BuildMapFromRoot(BuildMapState state, Expression expression) { var(properties, tables) = ComplexMapBuilder.BuildMap(state, expression); return( properties.Select(p => p.Convert(state)).ToArray(), tables.Select(p => p.Convert(state.WrappedSqlStatement)).ToArray()); }
static (StringBasedMappedProperty subject, IEnumerable <(StringBasedMappedProperty when, StringBasedMappedProperty then)> cases, IEnumerable <MappedTable> tables) GetCases( BuildMapState state, Expression caseExpression, MapType nextMap, string toPrefix = null) { var thenObject = caseExpression as MethodCallExpression; if (thenObject == null) { throw new SqlBuilderException(state.MappingPurpose, caseExpression); } var(isSubject, subject) = IsSubject(thenObject); if (isSubject) { var(subjectProperties, subjectTables) = ComplexMapBuilder.BuildMap(state, subject); var subjectP = subjectProperties.ToArray(); if (subjectP.Length != 1) { throw new SqlBuilderException(state.MappingPurpose, caseExpression); } return(subjectP[0], CodingConstants.Empty.Case, subjectTables); } var(isThen, thenResult) = IsThen(thenObject); if (!isThen) { throw new SqlBuilderException(state.MappingPurpose, thenObject); } var whenObject = thenObject.Object as MethodCallExpression; if (whenObject == null) { throw new SqlBuilderException(state.MappingPurpose, thenObject.Object); } var(isWhen, whenCondition) = IsWhen(whenObject); if (!isWhen) { throw new SqlBuilderException(state.MappingPurpose, whenObject); } var(whenProperties, whenTables) = ComplexMapBuilder.BuildMap(state, whenCondition); var(thenProperties, thenTables) = ComplexMapBuilder.BuildMap(state, thenResult); var whenP = whenProperties.ToArray(); var thenP = thenProperties.ToArray(); if (whenP.Length != 1 || thenP.Length != 1) { throw new SqlBuilderException(state.MappingPurpose, caseExpression); } var(sjt, cases, tables) = GetCases(state, whenObject.Object, MapType.Other, toPrefix); return( sjt, cases.Append((whenP[0], thenP[0])), tables.Concat(whenTables).Concat(thenTables) ); }