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);
        }
Beispiel #2
0
        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);
        }