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
{
///
/// 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.
///
///
public class SortBuilder : IEnumerable, ISortQueryBuilder
{
private string _constantOrderByClause;
private QueryBuilder _baseBuilder;
private Dialect _dialect;
private List> _sortExpressions;
private bool _useAltName;
private TableCollection _tables;
private IDataMapper _db;
private WhereBuilder _whereBuilder;
public SortBuilder()
{
// Used only for unit testing with mock frameworks
}
public SortBuilder(QueryBuilder baseBuilder, IDataMapper db, WhereBuilder whereBuilder, Dialect dialect, TableCollection tables, bool useAltName)
{
_baseBuilder = baseBuilder;
_db = db;
_whereBuilder = whereBuilder;
_dialect = dialect;
_sortExpressions = new List>();
_useAltName = useAltName;
_tables = tables;
}
#region - AndWhere / OrWhere -
public virtual SortBuilder OrWhere(Expression> filterExpression)
{
var orWhere = new WhereBuilder(_db.Command, _dialect, filterExpression, _tables, _useAltName, true);
_whereBuilder.Append(orWhere, WhereAppendType.OR);
return this;
}
public virtual SortBuilder OrWhere(string whereClause)
{
var orWhere = new WhereBuilder(whereClause, _useAltName);
_whereBuilder.Append(orWhere, WhereAppendType.OR);
return this;
}
public virtual SortBuilder AndWhere(Expression> filterExpression)
{
var andWhere = new WhereBuilder(_db.Command, _dialect, filterExpression, _tables, _useAltName, true);
_whereBuilder.Append(andWhere, WhereAppendType.AND);
return this;
}
public virtual SortBuilder AndWhere(string whereClause)
{
var andWhere = new WhereBuilder(whereClause, _useAltName);
_whereBuilder.Append(andWhere, WhereAppendType.AND);
return this;
}
#endregion
#region - Order -
internal SortBuilder Order(Type declaringType, string propertyName)
{
_sortExpressions.Add(new SortColumn(declaringType, propertyName, SortDirection.Asc));
return this;
}
internal SortBuilder OrderByDescending(Type declaringType, string propertyName)
{
_sortExpressions.Add(new SortColumn(declaringType, propertyName, SortDirection.Desc));
return this;
}
public virtual SortBuilder 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 OrderBy(Expression> sortExpression)
{
_sortExpressions.Add(new SortColumn(sortExpression, SortDirection.Asc));
return this;
}
public virtual SortBuilder OrderBy(Expression> sortExpression, SortDirection sortDirection)
{
_sortExpressions.Add(new SortColumn(sortExpression, sortDirection));
return this;
}
public virtual SortBuilder OrderByDescending(Expression> sortExpression)
{
_sortExpressions.Add(new SortColumn(sortExpression, SortDirection.Desc));
return this;
}
public virtual SortBuilder ThenBy(Expression> sortExpression)
{
_sortExpressions.Add(new SortColumn(sortExpression, SortDirection.Asc));
return this;
}
public virtual SortBuilder ThenBy(Expression> sortExpression, SortDirection sortDirection)
{
_sortExpressions.Add(new SortColumn(sortExpression, sortDirection));
return this;
}
public virtual SortBuilder ThenByDescending(Expression> sortExpression)
{
_sortExpressions.Add(new SortColumn(sortExpression, SortDirection.Desc));
return this;
}
#endregion
#region - Paging -
public virtual SortBuilder Take(int count)
{
_baseBuilder.Take(count);
return this;
}
public virtual SortBuilder Skip(int count)
{
_baseBuilder.Skip(count);
return this;
}
public virtual SortBuilder Page(int pageNumber, int pageSize)
{
_baseBuilder.Page(pageNumber, pageSize);
return this;
}
#endregion
#region - GetRowCount -
public virtual int GetRowCount()
{
return _baseBuilder.GetRowCount();
}
#endregion
#region - Count -
public virtual int Count()
{
return _baseBuilder.GetRowCount();
}
#endregion
#region - ToList / ToString / BuildQuery -
public virtual List 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 Operator -
public static implicit operator List(SortBuilder builder)
{
return builder.ToList();
}
#endregion
#region IEnumerable Members
public virtual IEnumerator GetEnumerator()
{
var list = this.ToList();
return list.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
}
}