using System; using System.Collections.Generic; using System.Linq; using System.Text; using DapperExtensions.Mapper; namespace DapperExtensions.Sql { public interface ISqlGenerator { IDapperExtensionsConfiguration Configuration { get; } string Select(IClassMapper classMap, IPredicate predicate, IList sort, IDictionary parameters); string SelectPaged(IClassMapper classMap, IPredicate predicate, IList sort, int page, int resultsPerPage, IDictionary parameters); string SelectSet(IClassMapper classMap, IPredicate predicate, IList sort, int firstResult, int maxResults, IDictionary parameters); string Count(IClassMapper classMap, IPredicate predicate, IDictionary parameters); string Insert(IClassMapper classMap); string Update(IClassMapper classMap, IPredicate predicate, IDictionary parameters); string Delete(IClassMapper classMap, IPredicate predicate, IDictionary parameters); string IdentitySql(IClassMapper classMap); string GetTableName(IClassMapper map); string GetColumnName(IClassMapper map, IPropertyMap property, bool includeAlias); string GetColumnName(IClassMapper map, string propertyName, bool includeAlias); bool SupportsMultipleStatements(); } public class SqlGeneratorImpl : ISqlGenerator { public SqlGeneratorImpl(IDapperExtensionsConfiguration configuration) { Configuration = configuration; } public IDapperExtensionsConfiguration Configuration { get; private set; } public virtual string Select(IClassMapper classMap, IPredicate predicate, IList sort, IDictionary parameters) { if (parameters == null) { throw new ArgumentNullException("Parameters"); } StringBuilder sql = new StringBuilder(string.Format("SELECT {0} FROM {1}", BuildSelectColumns(classMap), GetTableName(classMap))); if (predicate != null) { sql.Append(" WHERE ") .Append(predicate.GetSql(this, parameters)); } if (sort != null && sort.Any()) { sql.Append(" ORDER BY ") .Append(sort.Select(s => GetColumnName(classMap, s.PropertyName, false) + (s.Ascending ? " ASC" : " DESC")).AppendStrings()); } return sql.ToString(); } public virtual string SelectPaged(IClassMapper classMap, IPredicate predicate, IList sort, int page, int resultsPerPage, IDictionary parameters) { if (sort == null || !sort.Any()) { throw new ArgumentNullException("Sort", "Sort cannot be null or empty."); } if (parameters == null) { throw new ArgumentNullException("Parameters"); } StringBuilder innerSql = new StringBuilder(string.Format("SELECT {0} FROM {1}", BuildSelectColumns(classMap), GetTableName(classMap))); if (predicate != null) { innerSql.Append(" WHERE ") .Append(predicate.GetSql(this, parameters)); } string orderBy = sort.Select(s => GetColumnName(classMap, s.PropertyName, false) + (s.Ascending ? " ASC" : " DESC")).AppendStrings(); innerSql.Append(" ORDER BY " + orderBy); string sql = Configuration.Dialect.GetPagingSql(innerSql.ToString(), page, resultsPerPage, parameters); return sql; } public virtual string SelectSet(IClassMapper classMap, IPredicate predicate, IList sort, int firstResult, int maxResults, IDictionary parameters) { if (sort == null || !sort.Any()) { throw new ArgumentNullException("Sort", "Sort cannot be null or empty."); } if (parameters == null) { throw new ArgumentNullException("Parameters"); } StringBuilder innerSql = new StringBuilder(string.Format("SELECT {0} FROM {1}", BuildSelectColumns(classMap), GetTableName(classMap))); if (predicate != null) { innerSql.Append(" WHERE ") .Append(predicate.GetSql(this, parameters)); } string orderBy = sort.Select(s => GetColumnName(classMap, s.PropertyName, false) + (s.Ascending ? " ASC" : " DESC")).AppendStrings(); innerSql.Append(" ORDER BY " + orderBy); string sql = Configuration.Dialect.GetSetSql(innerSql.ToString(), firstResult, maxResults, parameters); return sql; } public virtual string Count(IClassMapper classMap, IPredicate predicate, IDictionary parameters) { if (parameters == null) { throw new ArgumentNullException("Parameters"); } StringBuilder sql = new StringBuilder(string.Format("SELECT COUNT(*) AS {0}Total{1} FROM {2}", Configuration.Dialect.OpenQuote, Configuration.Dialect.CloseQuote, GetTableName(classMap))); if (predicate != null) { sql.Append(" WHERE ") .Append(predicate.GetSql(this, parameters)); } return sql.ToString(); } public virtual string Insert(IClassMapper classMap) { var columns = classMap.Properties.Where(p => !(p.Ignored || p.IsReadOnly || p.KeyType == KeyType.Identity)); if (!columns.Any()) { throw new ArgumentException("No columns were mapped."); } var columnNames = columns.Select(p => GetColumnName(classMap, p, false)); var parameters = columns.Select(p => Configuration.Dialect.ParameterPrefix + p.Name); string sql = string.Format("INSERT INTO {0} ({1}) VALUES ({2})", GetTableName(classMap), columnNames.AppendStrings(), parameters.AppendStrings()); return sql; } public virtual string Update(IClassMapper classMap, IPredicate predicate, IDictionary parameters) { if (predicate == null) { throw new ArgumentNullException("Predicate"); } if (parameters == null) { throw new ArgumentNullException("Parameters"); } var columns = classMap.Properties.Where(p => !(p.Ignored || p.IsReadOnly || p.KeyType == KeyType.Identity)); if (!columns.Any()) { throw new ArgumentException("No columns were mapped."); } var setSql = columns.Select( p => string.Format( "{0} = {1}{2}", GetColumnName(classMap, p, false), Configuration.Dialect.ParameterPrefix, p.Name)); return string.Format("UPDATE {0} SET {1} WHERE {2}", GetTableName(classMap), setSql.AppendStrings(), predicate.GetSql(this, parameters)); } public virtual string Delete(IClassMapper classMap, IPredicate predicate, IDictionary parameters) { if (predicate == null) { throw new ArgumentNullException("Predicate"); } if (parameters == null) { throw new ArgumentNullException("Parameters"); } StringBuilder sql = new StringBuilder(string.Format("DELETE FROM {0}", GetTableName(classMap))); sql.Append(" WHERE ").Append(predicate.GetSql(this, parameters)); return sql.ToString(); } public virtual string IdentitySql(IClassMapper classMap) { return Configuration.Dialect.GetIdentitySql(GetTableName(classMap)); } public virtual string GetTableName(IClassMapper map) { return Configuration.Dialect.GetTableName(map.SchemaName, map.TableName, null); } public virtual string GetColumnName(IClassMapper map, IPropertyMap property, bool includeAlias) { string alias = null; if (property.ColumnName != property.Name && includeAlias) { alias = property.Name; } return Configuration.Dialect.GetColumnName(GetTableName(map), property.ColumnName, alias); } public virtual string GetColumnName(IClassMapper map, string propertyName, bool includeAlias) { IPropertyMap propertyMap = map.Properties.SingleOrDefault(p => p.Name.Equals(propertyName, StringComparison.CurrentCultureIgnoreCase)); if (propertyMap == null) { throw new ArgumentException(string.Format("Could not find '{0}' in Mapping.", propertyName)); } return GetColumnName(map, propertyMap, includeAlias); } public virtual bool SupportsMultipleStatements() { return Configuration.Dialect.SupportsMultipleStatements; } public virtual string BuildSelectColumns(IClassMapper classMap) { var columns = classMap.Properties .Where(p => !p.Ignored) .Select(p => GetColumnName(classMap, p, true)); return columns.AppendStrings(); } } }