using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.Linq.Expressions; 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, false, true); _whereBuilder.Append(orWhere, WhereAppendType.OR); return this; } public virtual SortBuilder OrWhere(string whereClause) { var orWhere = new WhereBuilder(whereClause, false); _whereBuilder.Append(orWhere, WhereAppendType.OR); return this; } public virtual SortBuilder AndWhere(Expression> filterExpression) { var andWhere = new WhereBuilder(_db.Command, _dialect, filterExpression, _tables, false, true); _whereBuilder.Append(andWhere, WhereAppendType.AND); return this; } public virtual SortBuilder AndWhere(string whereClause) { var andWhere = new WhereBuilder(whereClause, false); _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 - 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); if (!useAltName) sb.Append(_dialect.CreateToken(string.Format("{0}.{1}", table.Alias, columnName))); else sb.Append(_dialect.CreateToken(string.Format("{0}", 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 = ToList(); return list.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } #endregion } }