mirror of https://github.com/Radarr/Radarr
LINQ for paging missing episodes
This commit is contained in:
parent
a414a4663e
commit
d37c8c26c2
|
@ -72,6 +72,8 @@
|
||||||
<Compile Include="IDataMapper.cs" />
|
<Compile Include="IDataMapper.cs" />
|
||||||
<Compile Include="LazyLoaded.cs" />
|
<Compile Include="LazyLoaded.cs" />
|
||||||
<Compile Include="Mapping\FluentMappings.cs" />
|
<Compile Include="Mapping\FluentMappings.cs" />
|
||||||
|
<Compile Include="QGen\SqliteRowCountQueryDecorator.cs" />
|
||||||
|
<Compile Include="QGen\SqlitePagingQueryDecorator.cs" />
|
||||||
<Compile Include="UnitOfWork.cs" />
|
<Compile Include="UnitOfWork.cs" />
|
||||||
<Compile Include="UnitOfWorkSharedContext.cs" />
|
<Compile Include="UnitOfWorkSharedContext.cs" />
|
||||||
<Compile Include="Mapping\ColumnMapBuilder.cs" />
|
<Compile Include="Mapping\ColumnMapBuilder.cs" />
|
||||||
|
|
|
@ -241,7 +241,7 @@ namespace Marr.Data.QGen
|
||||||
string queryText = query.Generate();
|
string queryText = query.Generate();
|
||||||
|
|
||||||
_db.SqlMode = SqlModes.Text;
|
_db.SqlMode = SqlModes.Text;
|
||||||
int count = (int)_db.ExecuteScalar(queryText);
|
int count = Convert.ToInt32(_db.ExecuteScalar(queryText));
|
||||||
|
|
||||||
_db.SqlMode = previousSqlMode;
|
_db.SqlMode = previousSqlMode;
|
||||||
return count;
|
return count;
|
||||||
|
|
|
@ -56,6 +56,9 @@ namespace Marr.Data.QGen
|
||||||
case DB_SqlCeClient:
|
case DB_SqlCeClient:
|
||||||
return new RowCountQueryDecorator(innerQuery);
|
return new RowCountQueryDecorator(innerQuery);
|
||||||
|
|
||||||
|
case DB_SQLiteClient:
|
||||||
|
return new SqliteRowCountQueryDecorator(innerQuery);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException("Row count has not yet been implemented for this provider.");
|
throw new NotImplementedException("Row count has not yet been implemented for this provider.");
|
||||||
}
|
}
|
||||||
|
@ -74,6 +77,9 @@ namespace Marr.Data.QGen
|
||||||
case DB_SqlCeClient:
|
case DB_SqlCeClient:
|
||||||
return new PagingQueryDecorator(innerQuery, skip, take);
|
return new PagingQueryDecorator(innerQuery, skip, take);
|
||||||
|
|
||||||
|
case DB_SQLiteClient:
|
||||||
|
return new SqlitePagingQueryDecorator(innerQuery, skip, take);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException("Paging has not yet been implemented for this provider.");
|
throw new NotImplementedException("Paging has not yet been implemented for this provider.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
@ -77,13 +78,13 @@ namespace Marr.Data.QGen
|
||||||
|
|
||||||
internal SortBuilder<T> Order(Type declaringType, string propertyName)
|
internal SortBuilder<T> Order(Type declaringType, string propertyName)
|
||||||
{
|
{
|
||||||
_sortExpressions.Add(new SortColumn<T>(declaringType, propertyName, SortDirection.Asc));
|
_sortExpressions.Add(new SortColumn<T>(declaringType, propertyName, ListSortDirection.Ascending));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal SortBuilder<T> OrderByDescending(Type declaringType, string propertyName)
|
internal SortBuilder<T> OrderByDescending(Type declaringType, string propertyName)
|
||||||
{
|
{
|
||||||
_sortExpressions.Add(new SortColumn<T>(declaringType, propertyName, SortDirection.Desc));
|
_sortExpressions.Add(new SortColumn<T>(declaringType, propertyName, ListSortDirection.Descending));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,25 +104,37 @@ namespace Marr.Data.QGen
|
||||||
|
|
||||||
public virtual SortBuilder<T> OrderBy(Expression<Func<T, object>> sortExpression)
|
public virtual SortBuilder<T> OrderBy(Expression<Func<T, object>> sortExpression)
|
||||||
{
|
{
|
||||||
_sortExpressions.Add(new SortColumn<T>(sortExpression, SortDirection.Asc));
|
_sortExpressions.Add(new SortColumn<T>(sortExpression, ListSortDirection.Ascending));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual SortBuilder<T> OrderBy(Expression<Func<T, object>> sortExpression, ListSortDirection sortDirection)
|
||||||
|
{
|
||||||
|
_sortExpressions.Add(new SortColumn<T>(sortExpression, sortDirection));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual SortBuilder<T> OrderByDescending(Expression<Func<T, object>> sortExpression)
|
public virtual SortBuilder<T> OrderByDescending(Expression<Func<T, object>> sortExpression)
|
||||||
{
|
{
|
||||||
_sortExpressions.Add(new SortColumn<T>(sortExpression, SortDirection.Desc));
|
_sortExpressions.Add(new SortColumn<T>(sortExpression, ListSortDirection.Descending));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual SortBuilder<T> ThenBy(Expression<Func<T, object>> sortExpression)
|
public virtual SortBuilder<T> ThenBy(Expression<Func<T, object>> sortExpression)
|
||||||
{
|
{
|
||||||
_sortExpressions.Add(new SortColumn<T>(sortExpression, SortDirection.Asc));
|
_sortExpressions.Add(new SortColumn<T>(sortExpression, ListSortDirection.Ascending));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual SortBuilder<T> ThenBy(Expression<Func<T, object>> sortExpression, ListSortDirection sortDirection)
|
||||||
|
{
|
||||||
|
_sortExpressions.Add(new SortColumn<T>(sortExpression, sortDirection));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual SortBuilder<T> ThenByDescending(Expression<Func<T, object>> sortExpression)
|
public virtual SortBuilder<T> ThenByDescending(Expression<Func<T, object>> sortExpression)
|
||||||
{
|
{
|
||||||
_sortExpressions.Add(new SortColumn<T>(sortExpression, SortDirection.Desc));
|
_sortExpressions.Add(new SortColumn<T>(sortExpression, ListSortDirection.Descending));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +211,7 @@ namespace Marr.Data.QGen
|
||||||
string columnName = DataHelper.GetColumnName(sort.DeclaringType, sort.PropertyName, useAltName);
|
string columnName = DataHelper.GetColumnName(sort.DeclaringType, sort.PropertyName, useAltName);
|
||||||
sb.Append(_dialect.CreateToken(string.Format("{0}.{1}", table.Alias, columnName)));
|
sb.Append(_dialect.CreateToken(string.Format("{0}.{1}", table.Alias, columnName)));
|
||||||
|
|
||||||
if (sort.Direction == SortDirection.Desc)
|
if (sort.Direction == ListSortDirection.Descending)
|
||||||
sb.Append(" DESC");
|
sb.Append(" DESC");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
@ -9,7 +10,24 @@ namespace Marr.Data.QGen
|
||||||
{
|
{
|
||||||
public class SortColumn<T>
|
public class SortColumn<T>
|
||||||
{
|
{
|
||||||
|
[Obsolete("Use ListSortDirection instead")]
|
||||||
public SortColumn(Expression<Func<T, object>> sortExpression, SortDirection direction)
|
public SortColumn(Expression<Func<T, object>> sortExpression, SortDirection direction)
|
||||||
|
{
|
||||||
|
MemberExpression me = GetMemberExpression(sortExpression.Body);
|
||||||
|
DeclaringType = me.Expression.Type;
|
||||||
|
PropertyName = me.Member.Name;
|
||||||
|
Direction = GetSortDirection(direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use ListSortDirection instead")]
|
||||||
|
public SortColumn(Type declaringType, string propertyName, SortDirection direction)
|
||||||
|
{
|
||||||
|
DeclaringType = declaringType;
|
||||||
|
PropertyName = propertyName;
|
||||||
|
Direction = GetSortDirection(direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SortColumn(Expression<Func<T, object>> sortExpression, ListSortDirection direction)
|
||||||
{
|
{
|
||||||
MemberExpression me = GetMemberExpression(sortExpression.Body);
|
MemberExpression me = GetMemberExpression(sortExpression.Body);
|
||||||
DeclaringType = me.Expression.Type;
|
DeclaringType = me.Expression.Type;
|
||||||
|
@ -17,14 +35,14 @@ namespace Marr.Data.QGen
|
||||||
Direction = direction;
|
Direction = direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SortColumn(Type declaringType, string propertyName, SortDirection direction)
|
public SortColumn(Type declaringType, string propertyName, ListSortDirection direction)
|
||||||
{
|
{
|
||||||
DeclaringType = declaringType;
|
DeclaringType = declaringType;
|
||||||
PropertyName = propertyName;
|
PropertyName = propertyName;
|
||||||
Direction = direction;
|
Direction = direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SortDirection Direction { get; private set; }
|
public ListSortDirection Direction { get; private set; }
|
||||||
public Type DeclaringType { get; private set; }
|
public Type DeclaringType { get; private set; }
|
||||||
public string PropertyName { get; private set; }
|
public string PropertyName { get; private set; }
|
||||||
|
|
||||||
|
@ -40,6 +58,13 @@ namespace Marr.Data.QGen
|
||||||
|
|
||||||
return me;
|
return me;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ListSortDirection GetSortDirection(SortDirection direction)
|
||||||
|
{
|
||||||
|
if (direction == SortDirection.Desc) return ListSortDirection.Descending;
|
||||||
|
|
||||||
|
return ListSortDirection.Ascending;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SortDirection
|
public enum SortDirection
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Marr.Data.Mapping;
|
||||||
|
using Marr.Data.QGen.Dialects;
|
||||||
|
|
||||||
|
namespace Marr.Data.QGen
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Decorates the SelectQuery by wrapping it in a paging query.
|
||||||
|
/// </summary>
|
||||||
|
public class SqlitePagingQueryDecorator : IQuery
|
||||||
|
{
|
||||||
|
private SelectQuery _innerQuery;
|
||||||
|
private int _skip;
|
||||||
|
private int _take;
|
||||||
|
|
||||||
|
public SqlitePagingQueryDecorator(SelectQuery innerQuery, int skip, int take)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(innerQuery.OrderBy.ToString()))
|
||||||
|
{
|
||||||
|
throw new DataMappingException("A paged query must specify an order by clause.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_innerQuery = innerQuery;
|
||||||
|
_skip = skip;
|
||||||
|
_take = take;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Generate()
|
||||||
|
{
|
||||||
|
StringBuilder sql = new StringBuilder();
|
||||||
|
|
||||||
|
_innerQuery.BuildSelectClause(sql);
|
||||||
|
_innerQuery.BuildFromClause(sql);
|
||||||
|
_innerQuery.BuildJoinClauses(sql);
|
||||||
|
_innerQuery.BuildWhereClause(sql);
|
||||||
|
_innerQuery.BuildOrderClause(sql);
|
||||||
|
sql.AppendLine(String.Format(" LIMIT {0},{1}", _skip, _take));
|
||||||
|
|
||||||
|
return sql.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BuildSelectClause(StringBuilder sql)
|
||||||
|
{
|
||||||
|
List<string> appended = new List<string>();
|
||||||
|
|
||||||
|
sql.Append("SELECT ");
|
||||||
|
|
||||||
|
int startIndex = sql.Length;
|
||||||
|
|
||||||
|
// COLUMNS
|
||||||
|
foreach (Table join in _innerQuery.Tables)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < join.Columns.Count; i++)
|
||||||
|
{
|
||||||
|
var c = join.Columns[i];
|
||||||
|
|
||||||
|
if (sql.Length > startIndex && sql[sql.Length - 1] != ',')
|
||||||
|
sql.Append(",");
|
||||||
|
|
||||||
|
if (join is View)
|
||||||
|
{
|
||||||
|
string token = _innerQuery.Dialect.CreateToken(string.Concat(join.Alias, ".", _innerQuery.NameOrAltName(c.ColumnInfo)));
|
||||||
|
if (appended.Contains(token))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sql.Append(token);
|
||||||
|
appended.Add(token);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string token = string.Concat(join.Alias, ".", c.ColumnInfo.Name);
|
||||||
|
if (appended.Contains(token))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sql.Append(_innerQuery.Dialect.CreateToken(token));
|
||||||
|
|
||||||
|
if (_innerQuery.UseAltName && c.ColumnInfo.AltName != null && c.ColumnInfo.AltName != c.ColumnInfo.Name)
|
||||||
|
{
|
||||||
|
string altName = c.ColumnInfo.AltName;
|
||||||
|
sql.AppendFormat(" AS {0}", altName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Marr.Data.QGen
|
||||||
|
{
|
||||||
|
public class SqliteRowCountQueryDecorator : IQuery
|
||||||
|
{
|
||||||
|
private SelectQuery _innerQuery;
|
||||||
|
|
||||||
|
public SqliteRowCountQueryDecorator(SelectQuery innerQuery)
|
||||||
|
{
|
||||||
|
_innerQuery = innerQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Generate()
|
||||||
|
{
|
||||||
|
StringBuilder sql = new StringBuilder();
|
||||||
|
|
||||||
|
BuildSelectCountClause(sql);
|
||||||
|
_innerQuery.BuildFromClause(sql);
|
||||||
|
_innerQuery.BuildJoinClauses(sql);
|
||||||
|
_innerQuery.BuildWhereClause(sql);
|
||||||
|
|
||||||
|
return sql.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildSelectCountClause(StringBuilder sql)
|
||||||
|
{
|
||||||
|
sql.AppendLine("SELECT COUNT(*)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,7 +45,9 @@ namespace NzbDrone.Api
|
||||||
Mapper.CreateMap<PagingSpec<Episode>, PagingResource<EpisodeResource>>();
|
Mapper.CreateMap<PagingSpec<Episode>, PagingResource<EpisodeResource>>();
|
||||||
|
|
||||||
//History
|
//History
|
||||||
Mapper.CreateMap<Core.History.History, HistoryResource>();
|
Mapper.CreateMap<Core.History.History, HistoryResource>()
|
||||||
|
.ForMember(dest => dest.Episode, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.Series, opt => opt.Ignore());
|
||||||
Mapper.CreateMap<PagingSpec<Core.History.History>, PagingResource<HistoryResource>>();
|
Mapper.CreateMap<PagingSpec<Core.History.History>, PagingResource<HistoryResource>>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,24 @@ namespace NzbDrone.Api.History
|
||||||
// Series = series,
|
// Series = series,
|
||||||
Indexer = "nzbs.org",
|
Indexer = "nzbs.org",
|
||||||
Quality = new QualityModel(Quality.HDTV720p)
|
Quality = new QualityModel(Quality.HDTV720p)
|
||||||
|
},
|
||||||
|
new Core.History.History
|
||||||
|
{
|
||||||
|
Id = 2,
|
||||||
|
Date = DateTime.UtcNow.AddDays(-1),
|
||||||
|
// Episode = episode,
|
||||||
|
// Series = series,
|
||||||
|
Indexer = "nzbs.org",
|
||||||
|
Quality = new QualityModel(Quality.SDTV, true)
|
||||||
|
},
|
||||||
|
new Core.History.History
|
||||||
|
{
|
||||||
|
Id = 3,
|
||||||
|
Date = DateTime.UtcNow.AddDays(-5),
|
||||||
|
// Episode = episode,
|
||||||
|
// Series = series,
|
||||||
|
Indexer = "nzbs.org",
|
||||||
|
Quality = new QualityModel(Quality.WEBDL1080p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,8 +36,8 @@ namespace NzbDrone.Api.Missing
|
||||||
if (page == 0) page = 1;
|
if (page == 0) page = 1;
|
||||||
|
|
||||||
var sortKey = PrimitiveExtensions.ToNullSafeString(Request.Query.SortKey)
|
var sortKey = PrimitiveExtensions.ToNullSafeString(Request.Query.SortKey)
|
||||||
.Equals("SeriesTitle", StringComparison.InvariantCultureIgnoreCase)
|
.Equals("Series.Title", StringComparison.InvariantCultureIgnoreCase)
|
||||||
? "SeriesTitle"
|
? "Series.Title"
|
||||||
: "AirDate";
|
: "AirDate";
|
||||||
|
|
||||||
var sortDirection = PrimitiveExtensions.ToNullSafeString(Request.Query.SortDir)
|
var sortDirection = PrimitiveExtensions.ToNullSafeString(Request.Query.SortDir)
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System.ComponentModel;
|
||||||
|
using FluentAssertions;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.Datastore.PagingSpecExtenstionsTests
|
||||||
|
{
|
||||||
|
public class OrderByClauseFixture
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void Test()
|
||||||
|
{
|
||||||
|
var pagingSpec = new PagingSpec<Episode>
|
||||||
|
{
|
||||||
|
Page = 1,
|
||||||
|
PageSize = 10,
|
||||||
|
SortDirection = ListSortDirection.Ascending,
|
||||||
|
SortKey = "AirDate"
|
||||||
|
};
|
||||||
|
|
||||||
|
pagingSpec.OrderByClause().Should().NotBeNullOrEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -120,6 +120,7 @@
|
||||||
<Compile Include="Datastore\DatabaseRelationshipFixture.cs" />
|
<Compile Include="Datastore\DatabaseRelationshipFixture.cs" />
|
||||||
<Compile Include="Datastore\MappingExtentionFixture.cs" />
|
<Compile Include="Datastore\MappingExtentionFixture.cs" />
|
||||||
<Compile Include="Datastore\ObjectDatabaseFixture.cs" />
|
<Compile Include="Datastore\ObjectDatabaseFixture.cs" />
|
||||||
|
<Compile Include="Datastore\PagingSpecExtenstionsTests\OrderByClauseFixture.cs" />
|
||||||
<Compile Include="Download\DownloadClientTests\BlackholeProviderFixture.cs" />
|
<Compile Include="Download\DownloadClientTests\BlackholeProviderFixture.cs" />
|
||||||
<Compile Include="Download\DownloadClientTests\NzbgetProviderTests\DownloadNzbFixture.cs" />
|
<Compile Include="Download\DownloadClientTests\NzbgetProviderTests\DownloadNzbFixture.cs" />
|
||||||
<Compile Include="Download\DownloadClientTests\NzbgetProviderTests\QueueFixture.cs" />
|
<Compile Include="Download\DownloadClientTests\NzbgetProviderTests\QueueFixture.cs" />
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore
|
||||||
|
{
|
||||||
|
public static class PagingSpecExtensions
|
||||||
|
{
|
||||||
|
public static Expression<Func<TModel, object>> OrderByClause<TModel>(this PagingSpec<TModel> pagingSpec)
|
||||||
|
{
|
||||||
|
return CreateExpression<TModel>(pagingSpec.SortKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int PagingOffset<TModel>(this PagingSpec<TModel> pagingSpec)
|
||||||
|
{
|
||||||
|
return (pagingSpec.Page - 1)*pagingSpec.PageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Expression<Func<TModel, object>> CreateExpression<TModel>(string propertyName)
|
||||||
|
{
|
||||||
|
Type type = typeof(TModel);
|
||||||
|
ParameterExpression parameterExpression = Expression.Parameter(type, "x");
|
||||||
|
Expression expressionBody = parameterExpression;
|
||||||
|
|
||||||
|
var splitPropertyName = propertyName.Split('.').ToList();
|
||||||
|
|
||||||
|
foreach (var property in splitPropertyName)
|
||||||
|
{
|
||||||
|
expressionBody = Expression.Property(expressionBody, property);
|
||||||
|
}
|
||||||
|
|
||||||
|
expressionBody = Expression.Convert(expressionBody, typeof(object));
|
||||||
|
return Expression.Lambda<Func<TModel, object>>(expressionBody, parameterExpression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -67,10 +67,6 @@ namespace NzbDrone.Core.Datastore
|
||||||
Mapper.Entity<SeriesStatistics>().MapResultSet();
|
Mapper.Entity<SeriesStatistics>().MapResultSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static void RegisterMappers()
|
private static void RegisterMappers()
|
||||||
{
|
{
|
||||||
RegisterEmbeddedConverter();
|
RegisterEmbeddedConverter();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NzbDrone.Common.Messaging;
|
using NzbDrone.Common.Messaging;
|
||||||
|
@ -39,5 +40,7 @@ namespace NzbDrone.Core.History
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//public List<History> GetPagedHistory()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -211,6 +211,7 @@
|
||||||
<Compile Include="Datastore\ModelBase.cs" />
|
<Compile Include="Datastore\ModelBase.cs" />
|
||||||
<Compile Include="Datastore\BasicRepository.cs" />
|
<Compile Include="Datastore\BasicRepository.cs" />
|
||||||
<Compile Include="Datastore\PagingSpec.cs" />
|
<Compile Include="Datastore\PagingSpec.cs" />
|
||||||
|
<Compile Include="Datastore\PagingSpecExtensions.cs" />
|
||||||
<Compile Include="Datastore\RelationshipExtensions.cs" />
|
<Compile Include="Datastore\RelationshipExtensions.cs" />
|
||||||
<Compile Include="Datastore\TableMapping.cs" />
|
<Compile Include="Datastore\TableMapping.cs" />
|
||||||
<Compile Include="DecisionEngine\DownloadDecision.cs" />
|
<Compile Include="DecisionEngine\DownloadDecision.cs" />
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using FluentMigrator.Runner;
|
||||||
using Marr.Data;
|
using Marr.Data;
|
||||||
using Marr.Data.QGen;
|
using Marr.Data.QGen;
|
||||||
using NzbDrone.Common.Messaging;
|
using NzbDrone.Common.Messaging;
|
||||||
|
@ -65,40 +67,25 @@ namespace NzbDrone.Core.Tv
|
||||||
|
|
||||||
public PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials)
|
public PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials)
|
||||||
{
|
{
|
||||||
//TODO: Join in the series title so we can do sorting on it
|
|
||||||
if (!pagingSpec.SortKey.Equals("SeriesTitle", StringComparison.InvariantCultureIgnoreCase) &&
|
|
||||||
!pagingSpec.SortKey.Equals("AirDate", StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Invalid SortKey: " + pagingSpec.SortKey, "pagingSpec");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (includeSpecials)
|
if (includeSpecials)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException("Including specials is not available");
|
throw new NotImplementedException("Including specials is not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
var orderSql = String.Format("{0} {1}", pagingSpec.SortKey,
|
//This causes an issue if done within the LINQ Query
|
||||||
pagingSpec.SortDirection == ListSortDirection.Ascending ? "ASC" : "DESC");
|
|
||||||
|
|
||||||
var limitSql = String.Format("{0},{1}", (pagingSpec.Page - 1) * pagingSpec.PageSize, pagingSpec.PageSize);
|
|
||||||
|
|
||||||
var currentTime = DateTime.UtcNow;
|
var currentTime = DateTime.UtcNow;
|
||||||
_dataMapper.AddParameter("currentTime", currentTime);
|
|
||||||
|
|
||||||
var sql = String.Format(@"SELECT Episodes.*, Series.Title as SeriesTitle
|
pagingSpec.Records = Query.Join<Episode, Series>(JoinType.Inner, e => e.Series, (e, s) => e.SeriesId == s.Id)
|
||||||
FROM Episodes
|
.Where(e => e.EpisodeFileId == 0)
|
||||||
INNER JOIN Series
|
.AndWhere(e => e.SeasonNumber > 0)
|
||||||
ON Episodes.SeriesId = Series.Id
|
.AndWhere(e => e.AirDate <= currentTime)
|
||||||
WHERE EpisodeFileId = 0
|
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.SortDirection)
|
||||||
AND SeasonNumber > 0
|
.Skip(pagingSpec.PagingOffset())
|
||||||
AND AirDate <= @currentTime
|
.Take(pagingSpec.PageSize)
|
||||||
ORDER BY {0}
|
.ToList();
|
||||||
LIMIT {1}",
|
|
||||||
orderSql, limitSql
|
|
||||||
);
|
|
||||||
|
|
||||||
pagingSpec.Records = _dataMapper.Query<Episode>(sql);
|
//TODO: Use the same query for count and records
|
||||||
pagingSpec.TotalRecords = Query.Count(e => e.EpisodeFileId == 0 && e.SeasonNumber > 0 && e.AirDate <= currentTime);
|
pagingSpec.TotalRecords = Query.Where(e => e.EpisodeFileId == 0 && e.SeasonNumber > 0 && e.AirDate <= currentTime).GetRowCount();
|
||||||
|
|
||||||
return pagingSpec;
|
return pagingSpec;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<SolutionConfiguration>
|
<SolutionConfiguration>
|
||||||
<FileVersion>1</FileVersion>
|
<FileVersion>1</FileVersion>
|
||||||
<AutoEnableOnStartup>True</AutoEnableOnStartup>
|
<AutoEnableOnStartup>False</AutoEnableOnStartup>
|
||||||
<AllowParallelTestExecution>true</AllowParallelTestExecution>
|
<AllowParallelTestExecution>true</AllowParallelTestExecution>
|
||||||
<AllowTestsToRunInParallelWithThemselves>true</AllowTestsToRunInParallelWithThemselves>
|
|
||||||
<FrameworkUtilisationTypeForNUnit>UseDynamicAnalysis</FrameworkUtilisationTypeForNUnit>
|
<FrameworkUtilisationTypeForNUnit>UseDynamicAnalysis</FrameworkUtilisationTypeForNUnit>
|
||||||
<FrameworkUtilisationTypeForGallio>Disabled</FrameworkUtilisationTypeForGallio>
|
<FrameworkUtilisationTypeForGallio>Disabled</FrameworkUtilisationTypeForGallio>
|
||||||
<FrameworkUtilisationTypeForMSpec>Disabled</FrameworkUtilisationTypeForMSpec>
|
<FrameworkUtilisationTypeForMSpec>Disabled</FrameworkUtilisationTypeForMSpec>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
define(['app', 'History/Model'], function () {
|
define(['app', 'History/Model'], function () {
|
||||||
NzbDrone.Missing.Collection = Backbone.PageableCollection.extend({
|
NzbDrone.History.Collection = Backbone.PageableCollection.extend({
|
||||||
url : NzbDrone.Constants.ApiRoot + '/history',
|
url : NzbDrone.Constants.ApiRoot + '/history',
|
||||||
model : NzbDrone.History.Model,
|
model : NzbDrone.History.Model,
|
||||||
|
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
<i class="icon-search x-search" title="Search"></i>
|
<i class="icon-remove x-remove" title="Remove"></i>
|
||||||
|
<i class="icon-repeat x-redownload" title="Re-Download"></i>
|
|
@ -1,2 +0,0 @@
|
||||||
|
|
||||||
{{seasonNumber}}x{{paddedEpisodeNumber}}
|
|
|
@ -18,11 +18,18 @@ define([
|
||||||
showTable: function () {
|
showTable: function () {
|
||||||
|
|
||||||
var columns = [
|
var columns = [
|
||||||
|
{
|
||||||
|
name : 'indexer',
|
||||||
|
label : '',
|
||||||
|
editable : false,
|
||||||
|
cell : Backgrid.TemplateBackedCell.extend({ template: 'History/IndexerTemplate' }),
|
||||||
|
headerCell: 'nzbDrone'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name : 'seriesTitle',
|
name : 'seriesTitle',
|
||||||
label : 'Series Title',
|
label : 'Series Title',
|
||||||
editable : false,
|
editable : false,
|
||||||
cell : Backgrid.TemplateBackedCell.extend({ template: 'History/SeriesTitleTemplate' }),
|
cell : Backgrid.TemplateBackedCell.extend({ template: 'Missing/SeriesTitleTemplate' }),
|
||||||
headerCell: 'nzbDrone'
|
headerCell: 'nzbDrone'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -30,11 +37,11 @@ define([
|
||||||
label : 'Episode',
|
label : 'Episode',
|
||||||
editable : false,
|
editable : false,
|
||||||
sortable : false,
|
sortable : false,
|
||||||
cell : Backgrid.TemplateBackedCell.extend({ template: 'History/EpisodeColumnTemplate' }),
|
cell : Backgrid.TemplateBackedCell.extend({ template: 'Missing/EpisodeColumnTemplate' }),
|
||||||
headerCell: 'nzbDrone'
|
headerCell: 'nzbDrone'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name : 'title',
|
name : 'episode.title',
|
||||||
label : 'Episode Title',
|
label : 'Episode Title',
|
||||||
editable : false,
|
editable : false,
|
||||||
sortable : false,
|
sortable : false,
|
||||||
|
@ -42,8 +49,15 @@ define([
|
||||||
headerCell: 'nzbDrone'
|
headerCell: 'nzbDrone'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name : 'airDate',
|
name : 'quality',
|
||||||
label : 'Air Date',
|
label : 'Quality',
|
||||||
|
editable : false,
|
||||||
|
cell : Backgrid.TemplateBackedCell.extend({ template: 'History/QualityTemplate' }),
|
||||||
|
headerCell: 'nzbDrone'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'date',
|
||||||
|
label : 'Grabbed',
|
||||||
editable : false,
|
editable : false,
|
||||||
cell : 'airDate',
|
cell : 'airDate',
|
||||||
headerCell: 'nzbDrone'
|
headerCell: 'nzbDrone'
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<img src="favicon.ico" alt="{{indexer}}"/>
|
|
@ -0,0 +1,5 @@
|
||||||
|
{{quality.quality.name}}
|
||||||
|
|
||||||
|
{{#if quality.proper}}
|
||||||
|
[PROPER]
|
||||||
|
{{/if}}
|
|
@ -1 +0,0 @@
|
||||||
<a href="series/details/{{series.titleSlug}}">{{series.title}}</a>
|
|
|
@ -20,7 +20,7 @@ define([
|
||||||
|
|
||||||
var columns = [
|
var columns = [
|
||||||
{
|
{
|
||||||
name : 'seriesTitle',
|
name : 'series.Title',
|
||||||
label : 'Series Title',
|
label : 'Series Title',
|
||||||
editable : false,
|
editable : false,
|
||||||
cell : Backgrid.TemplateBackedCell.extend({ template: 'Missing/SeriesTitleTemplate' }),
|
cell : Backgrid.TemplateBackedCell.extend({ template: 'Missing/SeriesTitleTemplate' }),
|
||||||
|
|
Loading…
Reference in New Issue