public bool TryGenerate(IPContext context, string input, out IFilterParticle <TEntity> particle)
        {
            input = input.Trim();

            // Attempt to split the input by all "||" not enclosed in quotes or parenthesis.
            Regex regex      = new Regex("[||](?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))(?=(((?!\\)).)*\\()|[^\\(\\)]*$)");
            var   splitInput = regex
                               .Split(input)
                               .Where(x => !string.IsNullOrWhiteSpace(x));

            // If we dont end up with at least two parts, there's no OR operation here.
            if (splitInput.Count() < 2)
            {
                particle = null;
                return(false);
            }

            var trimmedInputs = splitInput.Select(x => x.Trim());

            // We parse each split input and OR it to the previous one.
            IFilterParticle <TEntity> resultParticle = null;

            foreach (var filter in trimmedInputs)
            {
                var cleanFilter = filter;

                if (filter.StartsWith("(") && filter.EndsWith(")"))
                {
                    cleanFilter = filter.Substring(1, filter.Length - 2);
                }

                if (!context.TryParseCsv(cleanFilter, out IEnumerable <IFilterParticle <TEntity> > particles))
                {
                    particle = null;
                    return(false);
                }

                var partialResult = particles.Count() > 1 ?
                                    new AndFilterParticle <TEntity>(particles.ToArray()) :
                                    particles.Single();

                resultParticle = resultParticle is null ?
                                 partialResult :
                                 new OrFilterParticle <TEntity>(resultParticle, partialResult);
            }

            particle = resultParticle;
            return(true);
        }
示例#2
0
        public static bool TryParseCsv <T>(
            this IPContext pContext,
            string input,
            out IEnumerable <IFilterParticle <T> > particles
            )
            where T : class
        {
            var particlesRaw = new List <IFilterParticle <T> >();

            var generators = new List <IParticleGenerator <IFilterParticle <T> > >()
            {
                // Default generators
                new ComplexLogicGenerator <T>()
            };

            generators.AddRange(pContext.GetGenerators <T, IFilterParticle <T> >());

            // Matching commas outside of quotes and parentheses
            Regex regx       = new Regex("[,](?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))(?=(((?!\\)).)*\\()|[^\\(\\)]*$)");
            var   splitInput = regx.Split(input);

            bool wasAbleToParse = true;

            foreach (var filter in splitInput)
            {
                IFilterParticle <T> particle = null;

                wasAbleToParse &= generators.Any(x => x.TryGenerate(pContext, filter, out particle));

                if (!(particle is null))
                {
                    particlesRaw.Add(particle);
                }
            }

            particles = wasAbleToParse ?
                        particlesRaw :
                        Array.Empty <IFilterParticle <T> >();

            return(wasAbleToParse);
        }
示例#3
0
        public bool TryGenerate(IPContext context, string input, out IFilterParticle <TEntity> particle)
        {
            input = input.Trim();

            // Attempt to capture field name from filter string.
            var nameMatch = Regex.Match(input, "^([A-Za-z0-9_]*)");

            if (!nameMatch.Success || nameMatch.Length == 0)
            {
                particle = null;
                return(false);
            }

            // Validate the property by name
            if (!TryGetPropertyByAlias(nameMatch.Value, out PropertyInfo property))
            {
                particle = null;
                return(false);
            }

            // Remove the name out of the filter string.
            var remaining = input.Substring(nameMatch.Length).TrimStart();

            // Attempt to capture operator from filter string.
            // Keys are ordered by descending length to always match the longest one possible first. (eg, "!=" instead "=")
            var operatorKey = SymbolMapper.Symbols.FirstOrDefault(o => remaining.StartsWith(o));

            if (operatorKey is null)
            {
                particle = null;
                return(false);
            }

            var op = SymbolMapper.Map(operatorKey);

            // Remove the operator out of the remaining filter string.
            var value = remaining.Substring(operatorKey.Length).Trim();

            // If encased in double quotes, we remove them.
            if (value.StartsWith("\"") && value.EndsWith("\""))
            {
                value = value.Substring(1, value.Length - 2);
            }

            try
            {
                // Attempt to convert/cast the value to the type of the property.
                var converter = TypeDescriptor.GetConverter(property.PropertyType);

                dynamic typedValue = converter.CanConvertFrom(value.GetType())
                    ? converter.ConvertFrom(value)
                    : Convert.ChangeType(value, property.PropertyType);

                // We generate our particle
                Type[] typeArgs = { typeof(TEntity), property.PropertyType };
                Type   byPropertyParticleType = typeof(ByPropertyParticle <,>).MakeGenericType(typeArgs);
                particle = (IFilterParticle <TEntity>)Activator.CreateInstance(byPropertyParticleType, property, op, typedValue);

                return(true);
            }
            catch
            {
                particle = null;
                return(false);
            }
        }