nuget-extensions/nuget-commands/src.2.8/QueryBuilder.cs (70 lines of code) (raw):

using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using JetBrains.Annotations; using NuGet; namespace JetBrains.TeamCity.NuGet.ExtendedCommands { public static class QueryBuilder { [NotNull] public static Expression GenerateQuery(PackageFetchOption fetchOption, IEnumerable<string> ids, ParameterExpression param) { var idFilter = GeneratePackageIdFilter(ids, param); switch (fetchOption) { case PackageFetchOption.IncludeAll: return idFilter; case PackageFetchOption.IncludeLatest: { var pi = typeof(IPackage).GetProperty("IsLatestVersion"); if (pi == null) goto case PackageFetchOption.IncludeAll; return Expression.And(Expression.Property(param, pi), idFilter); } case PackageFetchOption.IncludeLatestAndPrerelease: { var pi = typeof(IPackage).GetProperty("IsAbsoluteLatestVersion"); if (pi == null) goto case PackageFetchOption.IncludeAll; return Expression.And(Expression.Property(param, pi), idFilter); } default: throw new Exception("Unexpected PackageFetchOption: " + fetchOption); } } [NotNull] public static Expression GeneratePackageIdFilter(IEnumerable<string> ids, ParameterExpression param) { var toLower = typeof (string).GetMethod("ToLower", new Type[0]); var idProperty = typeof(IPackageName).GetProperty("Id"); var expressions = ids .Distinct() .Select(id => Expression.Equal(Expression.Call(Expression.Property(param, idProperty), toLower), Expression.Constant(id.ToLower()))) .ToList(); while (expressions.Count > 1) { var left = expressions.Where((x, i) => i % 2 == 0).ToList(); var right = expressions.Where((x, i) => i % 2 == 1).ToList(); expressions = ZipEx(left, right, Expression.Or).ToList(); } if (expressions.Count == 0) return Expression.Constant(true); return expressions.Single(); } private static IEnumerable<T> ZipEx<T>(IEnumerable<T> left, IEnumerable<T> right, Func<T, T, T> zip) { var enuLeft = left.GetEnumerator(); var enuRight = right.GetEnumerator(); bool hasLeft; bool hasRight; do { hasLeft = enuLeft.MoveNext(); hasRight = enuRight.MoveNext(); if (hasLeft && hasRight) yield return zip(enuLeft.Current, enuRight.Current); else if (hasLeft) yield return enuLeft.Current; else if (hasRight) yield return enuRight.Current; } while (hasLeft || hasRight); } } }