mirror of https://github.com/Sonarr/Sonarr
247 lines
7.5 KiB
C#
247 lines
7.5 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Text;
|
|||
|
using System.Linq.Expressions;
|
|||
|
using System.Reflection;
|
|||
|
using Marr.Data.QGen.Dialects;
|
|||
|
|
|||
|
namespace Marr.Data.QGen
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// This class is responsible for creating an "ORDER BY" clause.
|
|||
|
/// It uses chaining methods to provide a fluent interface.
|
|||
|
/// It also has some methods that coincide with Linq methods, to provide Linq compatibility.
|
|||
|
/// </summary>
|
|||
|
/// <typeparam name="T"></typeparam>
|
|||
|
public class SortBuilder<T> : IEnumerable<T>, ISortQueryBuilder
|
|||
|
{
|
|||
|
private string _constantOrderByClause;
|
|||
|
private QueryBuilder<T> _baseBuilder;
|
|||
|
private Dialect _dialect;
|
|||
|
private List<SortColumn<T>> _sortExpressions;
|
|||
|
private bool _useAltName;
|
|||
|
private TableCollection _tables;
|
|||
|
private IDataMapper _db;
|
|||
|
private WhereBuilder<T> _whereBuilder;
|
|||
|
|
|||
|
public SortBuilder()
|
|||
|
{
|
|||
|
// Used only for unit testing with mock frameworks
|
|||
|
}
|
|||
|
|
|||
|
public SortBuilder(QueryBuilder<T> baseBuilder, IDataMapper db, WhereBuilder<T> whereBuilder, Dialect dialect, TableCollection tables, bool useAltName)
|
|||
|
{
|
|||
|
_baseBuilder = baseBuilder;
|
|||
|
_db = db;
|
|||
|
_whereBuilder = whereBuilder;
|
|||
|
_dialect = dialect;
|
|||
|
_sortExpressions = new List<SortColumn<T>>();
|
|||
|
_useAltName = useAltName;
|
|||
|
_tables = tables;
|
|||
|
}
|
|||
|
|
|||
|
#region - AndWhere / OrWhere -
|
|||
|
|
|||
|
public virtual SortBuilder<T> OrWhere(Expression<Func<T, bool>> filterExpression)
|
|||
|
{
|
|||
|
var orWhere = new WhereBuilder<T>(_db.Command, _dialect, filterExpression, _tables, _useAltName, true);
|
|||
|
_whereBuilder.Append(orWhere, WhereAppendType.OR);
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
public virtual SortBuilder<T> OrWhere(string whereClause)
|
|||
|
{
|
|||
|
var orWhere = new WhereBuilder<T>(whereClause, _useAltName);
|
|||
|
_whereBuilder.Append(orWhere, WhereAppendType.OR);
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
public virtual SortBuilder<T> AndWhere(Expression<Func<T, bool>> filterExpression)
|
|||
|
{
|
|||
|
var andWhere = new WhereBuilder<T>(_db.Command, _dialect, filterExpression, _tables, _useAltName, true);
|
|||
|
_whereBuilder.Append(andWhere, WhereAppendType.AND);
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
public virtual SortBuilder<T> AndWhere(string whereClause)
|
|||
|
{
|
|||
|
var andWhere = new WhereBuilder<T>(whereClause, _useAltName);
|
|||
|
_whereBuilder.Append(andWhere, WhereAppendType.AND);
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region - Order -
|
|||
|
|
|||
|
internal SortBuilder<T> Order(Type declaringType, string propertyName)
|
|||
|
{
|
|||
|
_sortExpressions.Add(new SortColumn<T>(declaringType, propertyName, SortDirection.Asc));
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
internal SortBuilder<T> OrderByDescending(Type declaringType, string propertyName)
|
|||
|
{
|
|||
|
_sortExpressions.Add(new SortColumn<T>(declaringType, propertyName, SortDirection.Desc));
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
public virtual SortBuilder<T> OrderBy(string orderByClause)
|
|||
|
{
|
|||
|
if (string.IsNullOrEmpty(orderByClause))
|
|||
|
throw new ArgumentNullException("orderByClause");
|
|||
|
|
|||
|
if (!orderByClause.ToUpper().Contains("ORDER BY "))
|
|||
|
{
|
|||
|
orderByClause = orderByClause.Insert(0, " ORDER BY ");
|
|||
|
}
|
|||
|
|
|||
|
_constantOrderByClause = orderByClause;
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
public virtual SortBuilder<T> OrderBy(Expression<Func<T, object>> sortExpression)
|
|||
|
{
|
|||
|
_sortExpressions.Add(new SortColumn<T>(sortExpression, SortDirection.Asc));
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
public virtual SortBuilder<T> OrderByDescending(Expression<Func<T, object>> sortExpression)
|
|||
|
{
|
|||
|
_sortExpressions.Add(new SortColumn<T>(sortExpression, SortDirection.Desc));
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
public virtual SortBuilder<T> ThenBy(Expression<Func<T, object>> sortExpression)
|
|||
|
{
|
|||
|
_sortExpressions.Add(new SortColumn<T>(sortExpression, SortDirection.Asc));
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
public virtual SortBuilder<T> ThenByDescending(Expression<Func<T, object>> sortExpression)
|
|||
|
{
|
|||
|
_sortExpressions.Add(new SortColumn<T>(sortExpression, SortDirection.Desc));
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region - Paging -
|
|||
|
|
|||
|
public virtual SortBuilder<T> Take(int count)
|
|||
|
{
|
|||
|
_baseBuilder.Take(count);
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
public virtual SortBuilder<T> Skip(int count)
|
|||
|
{
|
|||
|
_baseBuilder.Skip(count);
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
public virtual SortBuilder<T> Page(int pageNumber, int pageSize)
|
|||
|
{
|
|||
|
_baseBuilder.Page(pageNumber, pageSize);
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region - GetRowCount -
|
|||
|
|
|||
|
public virtual int GetRowCount()
|
|||
|
{
|
|||
|
return _baseBuilder.GetRowCount();
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region - ToList / ToString / BuildQuery -
|
|||
|
|
|||
|
public virtual List<T> ToList()
|
|||
|
{
|
|||
|
return _baseBuilder.ToList();
|
|||
|
}
|
|||
|
|
|||
|
public virtual string BuildQuery()
|
|||
|
{
|
|||
|
return _baseBuilder.BuildQuery();
|
|||
|
}
|
|||
|
|
|||
|
public virtual string BuildQuery(bool useAltName)
|
|||
|
{
|
|||
|
if (!string.IsNullOrEmpty(_constantOrderByClause))
|
|||
|
{
|
|||
|
return _constantOrderByClause;
|
|||
|
}
|
|||
|
|
|||
|
StringBuilder sb = new StringBuilder();
|
|||
|
|
|||
|
foreach (var sort in _sortExpressions)
|
|||
|
{
|
|||
|
if (sb.Length > 0)
|
|||
|
sb.Append(",");
|
|||
|
|
|||
|
Table table = _tables.FindTable(sort.DeclaringType);
|
|||
|
|
|||
|
if (table == null)
|
|||
|
{
|
|||
|
string msg = string.Format("The property '{0} -> {1}' you are trying to reference in the 'ORDER BY' statement belongs to an entity that has not been joined in your query. To reference this property, you must join the '{0}' entity using the Join method.",
|
|||
|
sort.DeclaringType.Name,
|
|||
|
sort.PropertyName);
|
|||
|
|
|||
|
throw new DataMappingException(msg);
|
|||
|
}
|
|||
|
|
|||
|
string columnName = DataHelper.GetColumnName(sort.DeclaringType, sort.PropertyName, useAltName);
|
|||
|
sb.Append(_dialect.CreateToken(string.Format("{0}.{1}", table.Alias, columnName)));
|
|||
|
|
|||
|
if (sort.Direction == SortDirection.Desc)
|
|||
|
sb.Append(" DESC");
|
|||
|
}
|
|||
|
|
|||
|
if (sb.Length > 0)
|
|||
|
sb.Insert(0, " ORDER BY ");
|
|||
|
|
|||
|
return sb.ToString();
|
|||
|
}
|
|||
|
|
|||
|
public override string ToString()
|
|||
|
{
|
|||
|
return BuildQuery(_useAltName);
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region - Implicit List<T> Operator -
|
|||
|
|
|||
|
public static implicit operator List<T>(SortBuilder<T> builder)
|
|||
|
{
|
|||
|
return builder.ToList();
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region IEnumerable<T> Members
|
|||
|
|
|||
|
public virtual IEnumerator<T> GetEnumerator()
|
|||
|
{
|
|||
|
var list = this.ToList();
|
|||
|
return list.GetEnumerator();
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region IEnumerable Members
|
|||
|
|
|||
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
|||
|
{
|
|||
|
throw new NotImplementedException();
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
}
|
|||
|
}
|