diff --git a/Kendo.DynamicLinq.Tests/SerializationTests.cs b/Kendo.DynamicLinq.Tests/SerializationTests.cs index a023ad9..febb8f0 100644 --- a/Kendo.DynamicLinq.Tests/SerializationTests.cs +++ b/Kendo.DynamicLinq.Tests/SerializationTests.cs @@ -41,7 +41,7 @@ public void DataContractJsonSerializerSerializesAggregates() serializer.WriteObject(stream, people.AsQueryable().ToDataSourceResult(1, 2, null, null, new [] { new Aggregator { Aggregate = "sum", Field = "Age" - } })); + } },null)); var json = Encoding.UTF8.GetString(stream.ToArray()).Replace("\"__type\":\"DynamicClass2:#\",", ""); diff --git a/Kendo.DynamicLinq/DataSourceRequest.cs b/Kendo.DynamicLinq/DataSourceRequest.cs index ee2b358..7764eaa 100644 --- a/Kendo.DynamicLinq/DataSourceRequest.cs +++ b/Kendo.DynamicLinq/DataSourceRequest.cs @@ -20,7 +20,17 @@ public class DataSourceRequest /// /// Specifies the requested sort order. /// - public IEnumerable Sort { get; set; } + public IEnumerable Sort { get; set; } + + /// + /// Specifies the requested grouping. + /// + public IEnumerable Group { get; set; } + + /// + /// Specifies the requested aggregators. + /// + public IEnumerable Aggregate { get; set; } /// /// Specifies the requested filter. diff --git a/Kendo.DynamicLinq/DataSourceResult.cs b/Kendo.DynamicLinq/DataSourceResult.cs index d3b6ce1..80ba7f5 100644 --- a/Kendo.DynamicLinq/DataSourceResult.cs +++ b/Kendo.DynamicLinq/DataSourceResult.cs @@ -1,34 +1,38 @@ using System; -using System.Linq; using System.Collections; -using System.Collections.Generic; +using System.Linq; using System.Runtime.Serialization; namespace Kendo.DynamicLinq { /// - /// Describes the result of Kendo DataSource read operation. + /// Describes the result of Kendo DataSource read operation. /// [KnownType("GetKnownTypes")] public class DataSourceResult { /// - /// Represents a single page of processed data. + /// Represents a single page of processed data. /// public IEnumerable Data { get; set; } /// - /// The total number of records available. + /// Represents a single page of processed grouped data. + /// + public IEnumerable Group { get; set; } + + /// + /// The total number of records available. /// public int Total { get; set; } /// - /// Represents a requested aggregates. + /// Represents a requested aggregates. /// public object Aggregates { get; set; } /// - /// Used by the KnownType attribute which is required for WCF serialization support + /// Used by the KnownType attribute which is required for WCF serialization support /// /// private static Type[] GetKnownTypes() @@ -47,4 +51,4 @@ private static Type[] GetKnownTypes() .ToArray(); } } -} +} \ No newline at end of file diff --git a/Kendo.DynamicLinq/EnumerableExtenstions.cs b/Kendo.DynamicLinq/EnumerableExtenstions.cs new file mode 100644 index 0000000..c51250b --- /dev/null +++ b/Kendo.DynamicLinq/EnumerableExtenstions.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic; + +namespace Kendo.DynamicLinq +{ + public static class EnumerableExtenstions + { + public static dynamic GroupByMany(this IEnumerable elements, + IEnumerable groupSelectors) + { + //create a new list of Kendo Group Selectors + var selectors = new List>(groupSelectors.Count()); + foreach (var selector in groupSelectors) + { + //compile the Dynamic Expression Lambda for each one + var expression = + DynamicExpression.ParseLambda(typeof(TElement), typeof(object), selector.Field); + //add it to the list + selectors.Add(new GroupSelector + { + Selector = (Func) expression.Compile(), + Field = selector.Field, + Aggregates = selector.Aggregates + }); + } + //call the actual group by method + return elements.GroupByMany(selectors.ToArray()); + } + //returned value should look like the following + // [{ + // aggregates: { + // FIEL1DNAME: { + // FUNCTON1NAME: FUNCTION1VALUE, + // FUNCTON2NAME: FUNCTION2VALUE + // }, + // FIELD2NAME: { + // FUNCTON1NAME: FUNCTION1VALUE + // } + // }, + // field: FIELDNAME, // the field by which the data items are grouped + // hasSubgroups: true, // true if there are subgroups + // items: [ + // // either the subgroups or the data items + // { + // aggregates: { + // //nested group aggregates + // }, + // field: NESTEDGROUPFIELDNAME, + // hasSubgroups: false, + // items: [ + // // data records + // ], + // value: NESTEDGROUPVALUE + // }, + // //nestedgroup2, nestedgroup3, etc. + // ], + // value: VALUE // the group key + //} /* other groups */ + //] + //for more info check http://docs.telerik.com/kendo-ui/api/javascript/data/datasource#configuration-schema.groups + + public static dynamic GroupByMany(this IEnumerable elements, + params GroupSelector[] groupSelectors) + { + if (groupSelectors.Length > 0) + { + //get selector + var selector = groupSelectors.First(); + var nextSelectors = groupSelectors.Skip(1).ToArray(); //reduce the list recursively until zero + return + //group by and return + elements.GroupBy(selector.Selector).Select( + g => new GroupResult + { + Value = g.Key, + Aggregates = selector.Aggregates, + HasSubgroups = groupSelectors.Length > 1, + Count = g.Count(), + //recursivly group the next selectors + Items = g.GroupByMany(nextSelectors), + SelectorField = selector.Field + }); + } + //if there are not more group selectors return data + return elements; + } + } +} \ No newline at end of file diff --git a/Kendo.DynamicLinq/Group.cs b/Kendo.DynamicLinq/Group.cs new file mode 100644 index 0000000..aada77f --- /dev/null +++ b/Kendo.DynamicLinq/Group.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace Kendo.DynamicLinq +{ + public class Group : Sort + { + [DataMember(Name = "aggregates")] + public IEnumerable Aggregates { get; set; } + } +} \ No newline at end of file diff --git a/Kendo.DynamicLinq/GroupResult.cs b/Kendo.DynamicLinq/GroupResult.cs new file mode 100644 index 0000000..68357e5 --- /dev/null +++ b/Kendo.DynamicLinq/GroupResult.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace Kendo.DynamicLinq +{ + [DataContract(Name = "groupresult")] + public class GroupResult + { + //small letter properties are kendo js properties so please execuse the warnings + //for more info check http://docs.telerik.com/kendo-ui/api/javascript/data/datasource#configuration-schema.groups + [DataMember(Name = "value")] + public object Value { get; set; } + + public string SelectorField { get; set; } + [DataMember(Name = "field")] + public string Field + { + get { return string.Format("{0} ({1})", this.SelectorField, this.Count); } + } + public int Count { get; set; } + + [DataMember(Name = "aggregates")] + public IEnumerable Aggregates { get; set; } + + [DataMember(Name = "items")] + public dynamic Items { get; set; } + + [DataMember(Name = "hasSubgroups")] + public bool HasSubgroups { get; set; } // true if there are subgroups + + public override string ToString() + { + return string.Format("{0} ({1})", this.Value, this.Count); + } + } +} \ No newline at end of file diff --git a/Kendo.DynamicLinq/GroupSelector.cs b/Kendo.DynamicLinq/GroupSelector.cs new file mode 100644 index 0000000..6fb2e90 --- /dev/null +++ b/Kendo.DynamicLinq/GroupSelector.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace Kendo.DynamicLinq +{ + public class GroupSelector + { + public Func Selector { get; set; } + public string Field { get; set; } + public IEnumerable Aggregates { get; set; } + + } +} \ No newline at end of file diff --git a/Kendo.DynamicLinq/Kendo.DynamicLinq.csproj b/Kendo.DynamicLinq/Kendo.DynamicLinq.csproj index 3c5fd88..6af882a 100644 --- a/Kendo.DynamicLinq/Kendo.DynamicLinq.csproj +++ b/Kendo.DynamicLinq/Kendo.DynamicLinq.csproj @@ -1,64 +1,69 @@ - - - - Release - AnyCPU - 8.0.30703 - 2.0 - {2BD75D53-E0EA-4995-8B0F-60AD709945AC} - Library - Properties - Kendo.DynamicLinq - Kendo.DynamicLinq - v4.0 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - ..\packages\System.Linq.Dynamic.1.0.0\lib\net40\System.Linq.Dynamic.dll - - - - - - - - - - - - - - - - - + + + + Release + AnyCPU + 8.0.30703 + 2.0 + {2BD75D53-E0EA-4995-8B0F-60AD709945AC} + Library + Properties + Kendo.DynamicLinq + Kendo.DynamicLinq + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + ..\packages\System.Linq.Dynamic.1.0.7\lib\net40\System.Linq.Dynamic.dll + True + + + + + + + + + + + + + + + + + + + + + + --> \ No newline at end of file diff --git a/Kendo.DynamicLinq/QueryableExtensions.cs b/Kendo.DynamicLinq/QueryableExtensions.cs index 7944e12..8c156d0 100644 --- a/Kendo.DynamicLinq/QueryableExtensions.cs +++ b/Kendo.DynamicLinq/QueryableExtensions.cs @@ -1,169 +1,329 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Dynamic; -using System.Linq.Expressions; -using DynamicExpression = System.Linq.Dynamic.DynamicExpression; - -namespace Kendo.DynamicLinq -{ - public static class QueryableExtensions - { - /// - /// Applies data processing (paging, sorting, filtering and aggregates) over IQueryable using Dynamic Linq. - /// - /// The type of the IQueryable. - /// The IQueryable which should be processed. - /// Specifies how many items to take. Configurable via the pageSize setting of the Kendo DataSource. - /// Specifies how many items to skip. - /// Specifies the current sort order. - /// Specifies the current filter. - /// Specifies the current aggregates. - /// A DataSourceResult object populated from the processed IQueryable. - public static DataSourceResult ToDataSourceResult(this IQueryable queryable, int take, int skip, IEnumerable sort, Filter filter, IEnumerable aggregates) - { - // Filter the data first - queryable = Filter(queryable, filter); - - // Calculate the total number of records (needed for paging) - var total = queryable.Count(); - - // Calculate the aggregates - var aggregate = Aggregate(queryable, aggregates); - - // Sort the data - queryable = Sort(queryable, sort); - - // Finally page the data - if (take > 0) - { - queryable = Page(queryable, take, skip); - } - - return new DataSourceResult - { - Data = queryable.ToList(), - Total = total, - Aggregates = aggregate - }; - } - - /// - /// Applies data processing (paging, sorting and filtering) over IQueryable using Dynamic Linq. - /// - /// The type of the IQueryable. - /// The IQueryable which should be processed. - /// Specifies how many items to take. Configurable via the pageSize setting of the Kendo DataSource. - /// Specifies how many items to skip. - /// Specifies the current sort order. - /// Specifies the current filter. - /// A DataSourceResult object populated from the processed IQueryable. - public static DataSourceResult ToDataSourceResult(this IQueryable queryable, int take, int skip, IEnumerable sort, Filter filter) - { - return queryable.ToDataSourceResult(take, skip, sort, filter, null); - } - - /// - /// Applies data processing (paging, sorting and filtering) over IQueryable using Dynamic Linq. - /// - /// The type of the IQueryable. - /// The IQueryable which should be processed. - /// The DataSourceRequest object containing take, skip, order, and filter data. - /// A DataSourceResult object populated from the processed IQueryable. - public static DataSourceResult ToDataSourceResult(this IQueryable queryable, DataSourceRequest request) - { - return queryable.ToDataSourceResult(request.Take, request.Skip, request.Sort, request.Filter, null); - } - - private static IQueryable Filter(IQueryable queryable, Filter filter) - { - if (filter != null && filter.Logic != null) - { - // Collect a flat list of all filters - var filters = filter.All(); - - // Get all filter values as array (needed by the Where method of Dynamic Linq) - var values = filters.Select(f => f.Value).ToArray(); - - // Create a predicate expression e.g. Field1 = @0 And Field2 > @1 - string predicate = filter.ToExpression(filters); - - // Use the Where method of Dynamic Linq to filter the data - queryable = queryable.Where(predicate, values); - } - - return queryable; - } - - private static object Aggregate(IQueryable queryable, IEnumerable aggregates) - { - if (aggregates != null && aggregates.Any()) - { - var objProps = new Dictionary(); - var groups = aggregates.GroupBy(g => g.Field); - Type type = null; - foreach (var group in groups) - { - var fieldProps = new Dictionary(); - foreach (var aggregate in group) - { - var prop = typeof (T).GetProperty(aggregate.Field); - var param = Expression.Parameter(typeof (T), "s"); - var selector = aggregate.Aggregate == "count" && (Nullable.GetUnderlyingType(prop.PropertyType) != null) - ? Expression.Lambda(Expression.NotEqual(Expression.MakeMemberAccess(param, prop), Expression.Constant(null, prop.PropertyType)), param) - : Expression.Lambda(Expression.MakeMemberAccess(param, prop), param); - var mi = aggregate.MethodInfo(typeof (T)); - if (mi == null) - continue; - - var val = queryable.Provider.Execute(Expression.Call(null, mi, - aggregate.Aggregate == "count" && (Nullable.GetUnderlyingType(prop.PropertyType) == null) - ? new[] { queryable.Expression } - : new[] { queryable.Expression, Expression.Quote(selector) })); - - fieldProps.Add(new DynamicProperty(aggregate.Aggregate, typeof(object)), val); - } - type = DynamicExpression.CreateClass(fieldProps.Keys); - var fieldObj = Activator.CreateInstance(type); - foreach (var p in fieldProps.Keys) - type.GetProperty(p.Name).SetValue(fieldObj, fieldProps[p], null); - objProps.Add(new DynamicProperty(group.Key, fieldObj.GetType()), fieldObj); - } - - type = DynamicExpression.CreateClass(objProps.Keys); - - var obj = Activator.CreateInstance(type); - - foreach (var p in objProps.Keys) - { - type.GetProperty(p.Name).SetValue(obj, objProps[p], null); - } - - return obj; - } - else - { - return null; - } - } - - private static IQueryable Sort(IQueryable queryable, IEnumerable sort) - { - if (sort != null && sort.Any()) - { - // Create ordering expression e.g. Field1 asc, Field2 desc - var ordering = String.Join(",", sort.Select(s => s.ToExpression())); - - // Use the OrderBy method of Dynamic Linq to sort the data - return queryable.OrderBy(ordering); - } - - return queryable; - } - - private static IQueryable Page(IQueryable queryable, int take, int skip) - { - return queryable.Skip(skip).Take(take); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic; +using System.Linq.Expressions; +using System.Reflection; +using DynamicExpression = System.Linq.Dynamic.DynamicExpression; + +namespace Kendo.DynamicLinq +{ + public static class QueryableExtensions + { + /// + /// Applies data processing (paging, sorting, filtering and aggregates) over IQueryable using Dynamic Linq. + /// + /// The type of the IQueryable. + /// The IQueryable which should be processed. + /// Specifies how many items to take. Configurable via the pageSize setting of the Kendo DataSource. + /// Specifies how many items to skip. + /// Specifies the current sort order. + /// Specifies the current filter. + /// Specifies the current aggregates. + /// A DataSourceResult object populated from the processed IQueryable. + public static DataSourceResult ToDataSourceResult(this IQueryable queryable, int take, int skip, + IEnumerable sort, Filter filter, IEnumerable aggregates, IEnumerable group) + { + //the way this extension works it pages the records using skip and take + //in order to do that we need at least one sorted property + if (sort != null && !sort.Any()) + { + var elementType = queryable.ElementType; + var properties = elementType.GetProperties().ToList(); + //by default make dir desc + var sortByObject = new Sort + { + Dir = "desc" + }; + PropertyInfo propertyInfo; + //look for property that is called id + if (properties.Any(p => p.Name.ToLower() == "id")) + { + propertyInfo = properties.FirstOrDefault(p => p.Name.ToLower() == "id"); + } + //or contains id + else if (properties.Any(p => p.Name.ToLower().Contains("id"))) + { + propertyInfo = properties.FirstOrDefault(p => p.Name.ToLower().Contains("id")); + } + //or just get the first property + else + { + propertyInfo = properties.FirstOrDefault(); + } + if (propertyInfo != null) + { + sortByObject.Field = propertyInfo.Name; + } + sort = new List {sortByObject}; + } + else + { + sort = new List(); + } + // Filter the data first + queryable = Filter(queryable, filter); + + // Calculate the total number of records (needed for paging) + var total = queryable.Count(); + + // Calculate the aggregates + var aggregate = Aggregate(queryable, aggregates); + + if (group != null && group.Any()) + { + foreach (var source in group.Reverse()) + { + sort = sort.Append(new Sort() + { + Field = source.Field, + Dir = source.Dir + }); + } + } + + // Sort the data + queryable = Sort(queryable, sort); + + // Finally page the data + if (take > 0) + { + queryable = Page(queryable, take, skip, sort.Any()); + } + + var result = new DataSourceResult + { + Total = total, + Aggregates = aggregate + }; + // Group By + if (group != null && group.Any()) + { + var groupedQuery = queryable.ToList().GroupByMany(group); + result.Group = groupedQuery; + } + else + { + result.Data = queryable.ToList(); + } + return result; + } + + /// + /// Applies data processing (paging, sorting and filtering) over IQueryable using Dynamic Linq. + /// + /// The type of the IQueryable. + /// The IQueryable which should be processed. + /// Specifies how many items to take. Configurable via the pageSize setting of the Kendo DataSource. + /// Specifies how many items to skip. + /// Specifies the current sort order. + /// Specifies the current filter. + /// A DataSourceResult object populated from the processed IQueryable. + public static DataSourceResult ToDataSourceResult(this IQueryable queryable, int take, int skip, + IEnumerable sort, Filter filter) + { + return queryable.ToDataSourceResult(take, skip, sort, filter, null, null); + } + + /// + /// Applies data processing (paging, sorting and filtering) over IQueryable using Dynamic Linq. + /// + /// The type of the IQueryable. + /// The IQueryable which should be processed. + /// The DataSourceRequest object containing take, skip, order, and filter data. + /// A DataSourceResult object populated from the processed IQueryable. + public static DataSourceResult ToDataSourceResult(this IQueryable queryable, DataSourceRequest request) + { + return queryable.ToDataSourceResult(request.Take, request.Skip, request.Sort, request.Filter, null, + request.Group); + } + + public static IEnumerable Append(this IEnumerable source, T item) + { + foreach (T i in source) + yield return i; + + yield return item; + } + + public static IEnumerable Prepend(this IEnumerable source, T item) + { + yield return item; + + foreach (T i in source) + yield return i; + } + + private static IQueryable Filter(IQueryable queryable, Filter filter) + { + if ((filter != null) && (filter.Logic != null)) + { + // Collect a flat list of all filters + var filters = filter.All(); + + // Get all filter values as array (needed by the Where method of Dynamic Linq) + var values = filters.Select(f => f.Value is string ? f.Value.ToString().ToLower() : f.Value).ToArray(); + + ////Add toLower() for all filter Fields with type of string in the values + for (var i = 0; i < values.Length; i++) + { + if (values[i] is string) + { + filters[i].Field = string.Format("{0}.ToString().ToLower()", filters[i].Field); + } + // when we have a decimal value it gets converted to double and the query will break + if (values[i] is double) + { + values[i] = Convert.ToDecimal(values[i]); + } + if (values[i] is DateTime) + { + var dateTimeFilterValue = (DateTime) values[i]; + values[i] = new DateTime(dateTimeFilterValue.Year, dateTimeFilterValue.Month, + dateTimeFilterValue.Day, 0, 0, 0); + } + } + + var valuesList = values.ToList(); + + //Remove duplicate filters + //NOTE: we loop, and don't use .distinct for a reason! + //There is a miniscule chance different columns will filter by the same value, in which case using distinct will remove too many filters + for (int i = filters.Count - 1; i >= 0; i--) + { + var previousFilter = filters.ElementAtOrDefault(i - 1); + + if (previousFilter != null && filters[i].Equals(previousFilter)) + { + filters.RemoveAt(i); + + valuesList.RemoveAt(i); + } + } + var filtersList = filters.ToList(); + for (int i = 0; i < filters.Count; i++) + { + if (filters[i].Value is DateTime && filters[i].Operator == "eq") + { + var filterToEdit = filtersList[i]; + + //Copy the date from the filter + var baseDate = ((DateTime) filters[i].Value).Date; + + //Instead of comparing for exact equality, we compare as greater than the start of the day... + filterToEdit.Value = new DateTime(baseDate.Year, baseDate.Month, baseDate.Day, 0, 0, 0); + filterToEdit.Operator = "gte"; + valuesList[i] = filterToEdit.Value; + + //...and less than the end of that same day (we're making an additional filter here) + var newFilter = new Filter() + { + Value = new DateTime(baseDate.Year, baseDate.Month, baseDate.Day, 23, 59, 59), + Field = filters[i].Field, + Filters = filters[i].Filters, + Operator = "lte", + Logic = "and" + }; + + //Add that additional filter to the list of filters + filtersList.Add(newFilter); + valuesList.Add(newFilter.Value); + } + } + + values = valuesList.ToArray(); + filters = filtersList; + //Set the filters, since we may have editted them + filter.Filters = filtersList; + + // Create a predicate expression e.g. Field1 = @0 And Field2 > @1 + var predicate = filter.ToExpression(filters); + + // Use the Where method of Dynamic Linq to filter the data + queryable = queryable.Where(predicate, values); + } + + return queryable; + } + + private static object Aggregate(IQueryable queryable, IEnumerable aggregates) + { + if ((aggregates != null) && aggregates.Any()) + { + var objProps = new Dictionary(); + var groups = aggregates.GroupBy(g => g.Field); + Type type = null; + foreach (var group in groups) + { + var fieldProps = new Dictionary(); + foreach (var aggregate in group) + { + var prop = typeof(T).GetProperty(aggregate.Field); + var param = Expression.Parameter(typeof(T), "s"); + var selector = (aggregate.Aggregate == "count") && + (Nullable.GetUnderlyingType(prop.PropertyType) != null) + ? Expression.Lambda( + Expression.NotEqual(Expression.MakeMemberAccess(param, prop), + Expression.Constant(null, prop.PropertyType)), param) + : Expression.Lambda(Expression.MakeMemberAccess(param, prop), param); + var mi = aggregate.MethodInfo(typeof(T)); + if (mi == null) + { + continue; + } + + var val = queryable.Provider.Execute(Expression.Call(null, mi, + (aggregate.Aggregate == "count") && + (Nullable.GetUnderlyingType(prop.PropertyType) == null) + ? new[] {queryable.Expression} + : new[] {queryable.Expression, Expression.Quote(selector)})); + + fieldProps.Add(new DynamicProperty(aggregate.Aggregate, typeof(object)), val); + } + type = DynamicExpression.CreateClass(fieldProps.Keys); + var fieldObj = Activator.CreateInstance(type); + foreach (var p in fieldProps.Keys) + { + type.GetProperty(p.Name).SetValue(fieldObj, fieldProps[p], null); + } + objProps.Add(new DynamicProperty(group.Key, fieldObj.GetType()), fieldObj); + } + + type = DynamicExpression.CreateClass(objProps.Keys); + + var obj = Activator.CreateInstance(type); + + foreach (var p in objProps.Keys) + { + type.GetProperty(p.Name).SetValue(obj, objProps[p], null); + } + + return obj; + } + return null; + } + + private static IQueryable Sort(IQueryable queryable, IEnumerable sort) + { + if ((sort != null) && sort.Any()) + { + // Create ordering expression e.g. Field1 asc, Field2 desc + var ordering = string.Join(",", sort.Reverse().Select(s => s.ToExpression())); + + // Use the OrderBy method of Dynamic Linq to sort the data + return queryable.OrderBy(ordering); + } + + return queryable; + } + + private static IQueryable Page(IQueryable queryable, int take, int skip, bool sorted) + { + if (sorted) + { + return queryable.Skip(skip).Take(take); + } + return queryable.Take(take); + } + } +} \ No newline at end of file diff --git a/Kendo.DynamicLinq/packages.config b/Kendo.DynamicLinq/packages.config index 616a92b..46cb869 100644 --- a/Kendo.DynamicLinq/packages.config +++ b/Kendo.DynamicLinq/packages.config @@ -1,4 +1,4 @@ - - - + + + \ No newline at end of file diff --git a/packages/System.Linq.Dynamic.1.0.0/System.Linq.Dynamic.1.0.0.nupkg b/packages/System.Linq.Dynamic.1.0.0/System.Linq.Dynamic.1.0.0.nupkg deleted file mode 100644 index a54625a..0000000 Binary files a/packages/System.Linq.Dynamic.1.0.0/System.Linq.Dynamic.1.0.0.nupkg and /dev/null differ diff --git a/packages/System.Linq.Dynamic.1.0.0/System.Linq.Dynamic.1.0.0.nuspec b/packages/System.Linq.Dynamic.1.0.0/System.Linq.Dynamic.1.0.0.nuspec deleted file mode 100644 index d007f95..0000000 --- a/packages/System.Linq.Dynamic.1.0.0/System.Linq.Dynamic.1.0.0.nuspec +++ /dev/null @@ -1,14 +0,0 @@ - - - - System.Linq.Dynamic - 1.0.0 - Microsoft - Microsoft - http://www.opensource.org/licenses/ms-pl - https://github.com/kahanu/System.Linq.Dynamic - false - This is the Microsoft assembly for the .Net 4.0 Dynamic language functionality. - system linq dynamic - - \ No newline at end of file diff --git a/packages/System.Linq.Dynamic.1.0.0/lib/net40/System.Linq.Dynamic.dll b/packages/System.Linq.Dynamic.1.0.0/lib/net40/System.Linq.Dynamic.dll deleted file mode 100644 index 4338697..0000000 Binary files a/packages/System.Linq.Dynamic.1.0.0/lib/net40/System.Linq.Dynamic.dll and /dev/null differ diff --git a/packages/System.Linq.Dynamic.1.0.7/NuGet.exe b/packages/System.Linq.Dynamic.1.0.7/NuGet.exe new file mode 100644 index 0000000..8dd7e45 Binary files /dev/null and b/packages/System.Linq.Dynamic.1.0.7/NuGet.exe differ diff --git a/packages/System.Linq.Dynamic.1.0.7/System.Linq.Dynamic.1.0.7.nupkg b/packages/System.Linq.Dynamic.1.0.7/System.Linq.Dynamic.1.0.7.nupkg new file mode 100644 index 0000000..3e22503 Binary files /dev/null and b/packages/System.Linq.Dynamic.1.0.7/System.Linq.Dynamic.1.0.7.nupkg differ diff --git a/packages/System.Linq.Dynamic.1.0.7/lib/net40/System.Linq.Dynamic.dll b/packages/System.Linq.Dynamic.1.0.7/lib/net40/System.Linq.Dynamic.dll new file mode 100644 index 0000000..46ff770 Binary files /dev/null and b/packages/System.Linq.Dynamic.1.0.7/lib/net40/System.Linq.Dynamic.dll differ diff --git a/packages/repositories.config b/packages/repositories.config index 30d0ea5..d0830f6 100644 --- a/packages/repositories.config +++ b/packages/repositories.config @@ -1,5 +1,5 @@ - - - - + + + + \ No newline at end of file