public static readonly CsTag <QueryFilterExpressionInfo> BeforeFilterTag = "BeforeFilter"; // TODO: Can we use this? public void GenerateCode(IConceptInfo conceptInfo, ICodeBuilder codeBuilder) { var info = (QueryFilterExpressionInfo)conceptInfo; string queryableType = $"IQueryable<Common.Queryable.{info.Source.Module.Name}_{info.Source.Name}>"; var parsedExpression = new ParsedExpression(info.Expression, new[] { queryableType, info.Parameter }, info, BeforeFilterTag.Evaluate(info)); string filterMethod = $@"public {queryableType} Filter{parsedExpression.MethodParametersAndBody} "; codeBuilder.InsertCode(filterMethod, RepositoryHelper.RepositoryMembers, info.Source); }
private string GetOptimizedFilterMethod(ComposableFilterByInfo info, string queryableType) { if (!_commonConceptsOptions.ComposableFilterByOptimizeLambda) { return(null); } string newLine = "\r\n "; // Extensions that add new arguments to the expression will be ignored, assuming that the additional arguments are not used in the expression body. string commentedAdditionalArguments = newLine + _suppressAdditionalArgumentsMessage + newLine + "// " + AdditionalParametersArgumentTag.Evaluate(info) + newLine + "// " + AdditionalParametersTypeTag.Evaluate(info) + newLine; var parsedExpression = new ParsedExpression(info.Expression, null, info, BeforeFilterTag.Evaluate(info) + commentedAdditionalArguments); if (parsedExpression.ExpressionParameters.Length < 3) { return(null); } string parameterSource = parsedExpression.ExpressionParameters[0].Name; string parameterRepository = parsedExpression.ExpressionParameters[1].Name; string parameterFilter = parsedExpression.ExpressionParameters[2].Name; // Trying to remove usage of expression arguments other then input source and filter parameters. var simplifiedMethodBody = parsedExpression.MethodBody; if (_commonConceptsOptions.ComposableFilterByOptimizeRepositoryAndContextUsage) { var repositoryRegex = new Regex($@"\b{parameterRepository}([\.,\)])"); simplifiedMethodBody = repositoryRegex.Replace(simplifiedMethodBody, "_domRepository$1"); } // Parameters 0 and 2 are standard Filter method parameters: input query and filter type. If no other parameters are used in the expression, // the expression can be simplified by transforming it directly to the standard Filter method without using lambda expressions // (build performance optimization for C# compiler). var nonStandardParameters = parsedExpression.ExpressionParameters.Where((p, index) => index != 0 && index != 2).Select(p => p.Name).ToList(); if (nonStandardParameters.Any(parameter => new Regex($@"\b{parameter}\b").IsMatch(simplifiedMethodBody))) { return(null); } else { return($@"public {queryableType} Filter({queryableType} {parameterSource}, {info.Parameter} {parameterFilter}){simplifiedMethodBody} "); } }
public void GenerateCode(IConceptInfo conceptInfo, ICodeBuilder codeBuilder) { var info = (RowPermissionsWriteInfo)conceptInfo; var queryableType = $"Common.Queryable.{info.Source.Module.Name}_{info.Source.Name}"; var methodArguments = new[] { $"IQueryable<{queryableType}>", "Common.DomRepository", "Common.ExecutionContext" }; var methodResult = $"Expression<Func<{queryableType}, bool>>"; var parsedExpression = new ParsedExpression(info.SimplifiedExpression, methodArguments, info); var method = $@"public {methodResult} {RowPermissionsWriteInfo.PermissionsExpressionName}{parsedExpression.MethodParametersAndBody} "; codeBuilder.InsertCode(method, RepositoryHelper.RepositoryMembers, info.Source); }
public static string CreateRuleExpressionMethod(ICodeBuilder codeBuilder, RowPermissionsSingleFunctionRuleInfo info) { var target = info.RowPermissionsFilters.DataStructure; var queryableType = $"Common.Queryable.{target.Module.Name}_{target.Name}"; string methodName = $"GetRowPermissionsRule_{info.Name}"; var methodParameters = new[] { "Common.ExecutionContext" }; string additionalParameters = $",\r\n // Additional parameters for backward compatibility, should be removed in future releases:" + $"\r\n IQueryable<{queryableType}> items, Common.DomRepository repository"; // TODO: Remove additionalParameters in next major release. The lambda expression (code snippet) in row permission concepts has only parameter "context", // but developers sometimes used 'repository' variable from the parent method that was accidentally available in the code snippet. // The additionalParameters will provide all previously available variables to avoid breaking changes in minor release. var parsedExpression = new ParsedExpression(info.FilterExpressionFunction, methodParameters, info, additionalParameters: additionalParameters); string filterMethod = $@"private Expression<Func<{queryableType}, bool>> {methodName}{parsedExpression.MethodParametersAndBody} "; codeBuilder.InsertCode(filterMethod, RepositoryHelper.RepositoryMembers, target); return(methodName); }
public void GenerateCode(IConceptInfo conceptInfo, ICodeBuilder codeBuilder) { var info = (ComputeForNewBaseItemsInfo)conceptInfo; var baseDS = info.Dependency_Extends.Base; var uniqueSuffix = DslUtility.NameOptionalModule(info.EntityComputedFrom.Source, baseDS.Module) + DslUtility.NameOptionalModule(info.EntityComputedFrom.Target, baseDS.Module); string saveFilterArgument; if (!string.IsNullOrWhiteSpace(info.FilterSaveExpression)) { string saveFilterMethodName = $"FilterSaveComputeForNewBaseItems_{uniqueSuffix}"; var extensionDS = info.Dependency_Extends.Extension; var parsedExpression = new ParsedExpression(info.FilterSaveExpression, new[] { $"IEnumerable<{extensionDS.FullName}>" }, info); string filterSaveMethod = $@"private IEnumerable<{extensionDS.FullName}> {saveFilterMethodName}{parsedExpression.MethodParametersAndBody} "; codeBuilder.InsertCode(filterSaveMethod, RepositoryHelper.RepositoryMembers, baseDS); saveFilterArgument = $", {saveFilterMethodName}"; } else { saveFilterArgument = ""; } string callRecomputeOnSave = $@"if (insertedNew.Any()) {{ Guid[] insertedIds = insertedNew.Select(item => item.ID).ToArray(); _domRepository.{info.EntityComputedFrom.Target.FullName}.{EntityComputedFromCodeGenerator.RecomputeFunctionName(info.EntityComputedFrom)}(insertedIds{saveFilterArgument}); }} "; codeBuilder.InsertCode(callRecomputeOnSave, WritableOrmDataStructureCodeGenerator.OnSaveTag1, baseDS); }
public void GenerateCode(IConceptInfo conceptInfo, ICodeBuilder codeBuilder) { var info = (DefaultValueInfo)conceptInfo; string propertyName = info.Property is ReferencePropertyInfo ? info.Property.Name + "ID" : info.Property.Name; var parsedExpression = new ParsedExpression(info.Expression, new[] { info.Property.DataStructure.FullName }, info); string getDefaultValue; if (parsedExpression.ResultLiteral != null) { getDefaultValue = parsedExpression.ResultLiteral; } else { string csPropertyType = _conceptMetadata.GetCsPropertyType(info.Property); if (string.IsNullOrEmpty(csPropertyType)) { throw new DslSyntaxException(info, $"{info.Property.GetKeywordOrTypeName()} is not supported" + $" for {info.GetKeywordOrTypeName()}, because it does not provide concept metadata for C# property type."); } string defaultValueMethod = $@"private {csPropertyType} DefaultValue_{propertyName}{parsedExpression.MethodParametersAndBody} "; codeBuilder.InsertCode(defaultValueMethod, RepositoryHelper.RepositoryMembers, info.Property.DataStructure); getDefaultValue = $"DefaultValue_{propertyName}(item)"; } string setDefaultValue = $@"if (item.{propertyName} == null {DefaultValueAndConditionTag.Evaluate(info)}) item.{propertyName} = {getDefaultValue}; "; codeBuilder.InsertCode(setDefaultValue, DefaultValuesCodeGenerator.SetDefaultValueTag, info.Dependency_DefaultValues); }