rebased with Marr.Data

there is a broken test.
This commit is contained in:
Keivan Beigi 2013-05-27 16:35:53 -07:00
parent 6e6df842a0
commit 261ce772de
8 changed files with 199 additions and 58 deletions

View File

@ -55,5 +55,20 @@ namespace Marr.Data.QGen.Dialects
return true; return true;
} }
} }
public virtual string StartsWithFormat
{
get { return "({0} LIKE {1} + '%')"; }
}
public virtual string EndsWithFormat
{
get { return "({0} LIKE '%' + {1})"; }
}
public virtual string ContainsFormat
{
get { return "({0} LIKE '%' + {1} + '%')"; }
}
} }
} }

View File

@ -14,5 +14,20 @@ namespace Marr.Data.QGen.Dialects
return "SELECT last_insert_rowid();"; return "SELECT last_insert_rowid();";
} }
} }
public override string StartsWithFormat
{
get { return "({0} LIKE {1} || '%')"; }
}
public override string EndsWithFormat
{
get { return "({0} LIKE '%' || {1})"; }
}
public override string ContainsFormat
{
get { return "({0} LIKE '%' || {1} || '%')"; }
}
} }
} }

View File

@ -20,25 +20,31 @@ namespace Marr.Data.QGen
{ {
#region - Private Members - #region - Private Members -
private Dialects.Dialect _dialect;
private DataMapper _db; private DataMapper _db;
private Dialects.Dialect _dialect;
private TableCollection _tables; private TableCollection _tables;
private WhereBuilder<T> _whereBuilder; private WhereBuilder<T> _whereBuilder;
private SortBuilder<T> _sortBuilder; private SortBuilder<T> _sortBuilder;
private bool _useAltName = false;
private bool _isGraph = false; private bool _isGraph = false;
private string _queryText; private bool _isFromView = false;
private List<MemberInfo> _childrenToLoad; private bool _isFromTable = false;
private bool _isJoin = false;
private bool _isManualQuery = false;
private bool _enablePaging = false; private bool _enablePaging = false;
private int _skip; private int _skip;
private int _take; private int _take;
private string _queryText;
private List<MemberInfo> _childrenToLoad;
private SortBuilder<T> SortBuilder private SortBuilder<T> SortBuilder
{ {
get get
{ {
// Lazy load // Lazy load
if (_sortBuilder == null) if (_sortBuilder == null)
_sortBuilder = new SortBuilder<T>(this, _db, _whereBuilder, _dialect, _tables, _useAltName); {
bool useAltNames = _isFromView || _isGraph || _isJoin;
_sortBuilder = new SortBuilder<T>(this, _db, _whereBuilder, _dialect, _tables, useAltNames);
}
return _sortBuilder; return _sortBuilder;
} }
@ -98,14 +104,19 @@ namespace Marr.Data.QGen
if (string.IsNullOrEmpty(viewName)) if (string.IsNullOrEmpty(viewName))
throw new ArgumentNullException("view"); throw new ArgumentNullException("view");
_useAltName = true; _isFromView = true;
// Replace the base table with a view with tables // Replace the base table with a view with tables
View view = new View(viewName, _tables.ToArray()); if (_tables[0] is View)
_tables.ReplaceBaseTable(view); {
(_tables[0] as View).Name = viewName;
}
else
{
View view = new View(viewName, _tables.ToArray());
_tables.ReplaceBaseTable(view);
}
//// Override the base table name
//_tables[0].Name = view;
return this; return this;
} }
@ -118,7 +129,7 @@ namespace Marr.Data.QGen
if (string.IsNullOrEmpty(table)) if (string.IsNullOrEmpty(table))
throw new ArgumentNullException("view"); throw new ArgumentNullException("view");
_useAltName = false; _isFromTable = true;
// Override the base table name // Override the base table name
_tables[0].Name = table; _tables[0].Name = table;
@ -130,6 +141,7 @@ namespace Marr.Data.QGen
/// </summary> /// </summary>
public virtual QueryBuilder<T> QueryText(string queryText) public virtual QueryBuilder<T> QueryText(string queryText)
{ {
_isManualQuery = true;
_queryText = queryText; _queryText = queryText;
return this; return this;
} }
@ -177,7 +189,6 @@ namespace Marr.Data.QGen
_tables.ReplaceBaseTable(view); _tables.ReplaceBaseTable(view);
_isGraph = true; _isGraph = true;
_useAltName = true;
return this; return this;
} }
@ -237,7 +248,8 @@ namespace Marr.Data.QGen
// Generate a row count query // Generate a row count query
string where = _whereBuilder != null ? _whereBuilder.ToString() : string.Empty; string where = _whereBuilder != null ? _whereBuilder.ToString() : string.Empty;
IQuery query = QueryFactory.CreateRowCountSelectQuery(_tables, _db, where, SortBuilder, _useAltName); bool useAltNames = _isFromView || _isGraph || _isJoin;
IQuery query = QueryFactory.CreateRowCountSelectQuery(_tables, _db, where, SortBuilder, useAltNames);
string queryText = query.Generate(); string queryText = query.Generate();
_db.SqlMode = SqlModes.Text; _db.SqlMode = SqlModes.Text;
@ -255,15 +267,17 @@ namespace Marr.Data.QGen
{ {
SqlModes previousSqlMode = _db.SqlMode; SqlModes previousSqlMode = _db.SqlMode;
ValidateQuery();
BuildQueryOrAppendClauses(); BuildQueryOrAppendClauses();
if (_isGraph) if (_isGraph || _isJoin)
{ {
_results = (List<T>)_db.QueryToGraph<T>(_queryText, EntGraph, _childrenToLoad); _results = (List<T>)_db.QueryToGraph<T>(_queryText, EntGraph, _childrenToLoad);
} }
else else
{ {
_results = (List<T>)_db.Query<T>(_queryText, _results, _useAltName); _results = (List<T>)_db.Query<T>(_queryText, _results, _isFromView);
} }
// Return to previous sql mode // Return to previous sql mode
@ -272,6 +286,33 @@ namespace Marr.Data.QGen
return _results; return _results;
} }
private void ValidateQuery()
{
if (_isManualQuery && _isFromView)
throw new InvalidOperationException("Cannot use FromView in conjunction with QueryText");
if (_isManualQuery && _isFromTable)
throw new InvalidOperationException("Cannot use FromTable in conjunction with QueryText");
if (_isManualQuery && _isJoin)
throw new InvalidOperationException("Cannot use Join in conjuntion with QueryText");
if (_isManualQuery && _enablePaging)
throw new InvalidOperationException("Cannot use Page, Skip or Take in conjunction with QueryText");
if (_isJoin && _isFromView)
throw new InvalidOperationException("Cannot use FromView in conjunction with Join");
if (_isJoin && _isFromTable)
throw new InvalidOperationException("Cannot use FromView in conjunction with Join");
if (_isJoin && _isGraph)
throw new InvalidOperationException("Cannot use Graph in conjunction with Join");
if (_isFromView && _isFromTable)
throw new InvalidOperationException("Cannot use FromView in conjunction with FromTable");
}
private void BuildQueryOrAppendClauses() private void BuildQueryOrAppendClauses()
{ {
if (_queryText == null) if (_queryText == null)
@ -302,14 +343,16 @@ namespace Marr.Data.QGen
// Generate a query // Generate a query
string where = _whereBuilder != null ? _whereBuilder.ToString() : string.Empty; string where = _whereBuilder != null ? _whereBuilder.ToString() : string.Empty;
bool useAltNames = _isFromView || _isGraph || _isJoin;
IQuery query = null; IQuery query = null;
if (_enablePaging) if (_enablePaging)
{ {
query = QueryFactory.CreatePagingSelectQuery(_tables, _db, where, SortBuilder, _useAltName, _skip, _take); query = QueryFactory.CreatePagingSelectQuery(_tables, _db, where, SortBuilder, useAltNames, _skip, _take);
} }
else else
{ {
query = QueryFactory.CreateSelectQuery(_tables, _db, where, SortBuilder, _useAltName); query = QueryFactory.CreateSelectQuery(_tables, _db, where, SortBuilder, useAltNames);
} }
_queryText = query.Generate(); _queryText = query.Generate();
@ -324,10 +367,11 @@ namespace Marr.Data.QGen
private ColumnMapCollection GetColumns(IEnumerable<string> entitiesToLoad) private ColumnMapCollection GetColumns(IEnumerable<string> entitiesToLoad)
{ {
// If QueryToGraph<T> and no child load entities are specified, load all children // If QueryToGraph<T> and no child load entities are specified, load all children
bool loadAllChildren = _useAltName && entitiesToLoad == null; bool useAltNames = _isFromView || _isGraph || _isJoin;
bool loadAllChildren = useAltNames && entitiesToLoad == null;
// If Query<T> // If Query<T>
if (!_useAltName) if (!useAltNames)
{ {
return MapRepository.Instance.GetColumns(typeof(T)); return MapRepository.Instance.GetColumns(typeof(T));
} }
@ -359,13 +403,17 @@ namespace Marr.Data.QGen
public virtual SortBuilder<T> Where<TObj>(Expression<Func<TObj, bool>> filterExpression) public virtual SortBuilder<T> Where<TObj>(Expression<Func<TObj, bool>> filterExpression)
{ {
_whereBuilder = new WhereBuilder<T>(_db.Command, _dialect, filterExpression, _tables, _useAltName, true); bool useAltNames = _isFromView || _isGraph;
bool addTablePrefixToColumns = true;
_whereBuilder = new WhereBuilder<T>(_db.Command, _dialect, filterExpression, _tables, useAltNames, addTablePrefixToColumns);
return SortBuilder; return SortBuilder;
} }
public virtual SortBuilder<T> Where(Expression<Func<T, bool>> filterExpression) public virtual SortBuilder<T> Where(Expression<Func<T, bool>> filterExpression)
{ {
_whereBuilder = new WhereBuilder<T>(_db.Command, _dialect, filterExpression, _tables, _useAltName, true); bool useAltNames = _isFromView || _isGraph;
bool addTablePrefixToColumns = true;
_whereBuilder = new WhereBuilder<T>(_db.Command, _dialect, filterExpression, _tables, useAltNames, addTablePrefixToColumns);
return SortBuilder; return SortBuilder;
} }
@ -379,7 +427,8 @@ namespace Marr.Data.QGen
whereClause = whereClause.Insert(0, " WHERE "); whereClause = whereClause.Insert(0, " WHERE ");
} }
_whereBuilder = new WhereBuilder<T>(whereClause, _useAltName); bool useAltNames = _isFromView || _isGraph || _isJoin;
_whereBuilder = new WhereBuilder<T>(whereClause, useAltNames);
return SortBuilder; return SortBuilder;
} }
@ -491,20 +540,21 @@ namespace Marr.Data.QGen
public virtual QueryBuilder<T> Join<TLeft, TRight>(JoinType joinType, Expression<Func<TLeft, IEnumerable<TRight>>> rightEntity, Expression<Func<TLeft, TRight, bool>> filterExpression) public virtual QueryBuilder<T> Join<TLeft, TRight>(JoinType joinType, Expression<Func<TLeft, IEnumerable<TRight>>> rightEntity, Expression<Func<TLeft, TRight, bool>> filterExpression)
{ {
_isJoin = true;
MemberInfo rightMember = (rightEntity.Body as MemberExpression).Member; MemberInfo rightMember = (rightEntity.Body as MemberExpression).Member;
return this.Join(joinType, rightMember, filterExpression); return this.Join(joinType, rightMember, filterExpression);
} }
public virtual QueryBuilder<T> Join<TLeft, TRight>(JoinType joinType, Expression<Func<TLeft, TRight>> rightEntity, Expression<Func<TLeft, TRight, bool>> filterExpression) public virtual QueryBuilder<T> Join<TLeft, TRight>(JoinType joinType, Expression<Func<TLeft, TRight>> rightEntity, Expression<Func<TLeft, TRight, bool>> filterExpression)
{ {
_isJoin = true;
MemberInfo rightMember = (rightEntity.Body as MemberExpression).Member; MemberInfo rightMember = (rightEntity.Body as MemberExpression).Member;
return this.Join(joinType, rightMember, filterExpression); return this.Join(joinType, rightMember, filterExpression);
} }
public virtual QueryBuilder<T> Join<TLeft, TRight>(JoinType joinType, MemberInfo rightMember, Expression<Func<TLeft, TRight, bool>> filterExpression) public virtual QueryBuilder<T> Join<TLeft, TRight>(JoinType joinType, MemberInfo rightMember, Expression<Func<TLeft, TRight, bool>> filterExpression)
{ {
_useAltName = true; _isJoin = true;
_isGraph = true;
if (!_childrenToLoad.ContainsMember(rightMember)) if (!_childrenToLoad.ContainsMember(rightMember))
_childrenToLoad.Add(rightMember); _childrenToLoad.Add(rightMember);

View File

@ -170,15 +170,6 @@ namespace Marr.Data.QGen
#endregion #endregion
#region - Count -
public virtual int Count()
{
return _baseBuilder.GetRowCount();
}
#endregion
#region - ToList / ToString / BuildQuery - #region - ToList / ToString / BuildQuery -
public virtual List<T> ToList() public virtual List<T> ToList()
@ -218,7 +209,7 @@ namespace Marr.Data.QGen
string columnName = DataHelper.GetColumnName(sort.DeclaringType, sort.PropertyName, useAltName); string columnName = DataHelper.GetColumnName(sort.DeclaringType, sort.PropertyName, useAltName);
if (!_useAltName) if (!useAltName)
sb.Append(_dialect.CreateToken(string.Format("{0}.{1}", table.Alias, columnName))); sb.Append(_dialect.CreateToken(string.Format("{0}.{1}", table.Alias, columnName)));
else else

View File

@ -30,6 +30,19 @@ namespace Marr.Data.QGen
public string Generate() public string Generate()
{ {
if (_innerQuery.IsView || _innerQuery.IsJoin)
{
return ComplexPaging();
}
else
{
return SimplePaging();
}
}
private string SimplePaging()
{
// Create paged query
StringBuilder sql = new StringBuilder(); StringBuilder sql = new StringBuilder();
_innerQuery.BuildSelectClause(sql); _innerQuery.BuildSelectClause(sql);
@ -42,6 +55,28 @@ namespace Marr.Data.QGen
return sql.ToString(); return sql.ToString();
} }
private string ComplexPaging()
{
var baseTable = _innerQuery.Tables.First();
StringBuilder sql = new StringBuilder();
_innerQuery.BuildSelectClause(sql);
sql.Append(" FROM (");
BuildSimpleInnerSelect(sql);
_innerQuery.BuildFromClause(sql);
_innerQuery.BuildWhereClause(sql);
sql.AppendLine(String.Format("LIMIT {0},{1}", _skip, _take));
sql.AppendFormat(") AS {0} ", _innerQuery.Dialect.CreateToken(baseTable.Alias));
_innerQuery.BuildJoinClauses(sql);
_innerQuery.BuildOrderClause(sql);
return sql.ToString();
}
public void BuildSelectClause(StringBuilder sql) public void BuildSelectClause(StringBuilder sql)
{ {
List<string> appended = new List<string>(); List<string> appended = new List<string>();
@ -86,5 +121,26 @@ namespace Marr.Data.QGen
} }
} }
} }
private void BuildSimpleInnerSelect(StringBuilder sql)
{
sql.Append("SELECT ");
int startIndex = sql.Length;
// COLUMNS
var join = _innerQuery.Tables.First();
for (int i = 0; i < join.Columns.Count; i++)
{
var c = join.Columns[i];
if (sql.Length > startIndex)
sql.Append(",");
string token = c.ColumnInfo.Name;
sql.Append(_innerQuery.Dialect.CreateToken(token));
}
}
} }
} }

View File

@ -24,7 +24,7 @@ namespace Marr.Data.QGen
private MapRepository _repos; private MapRepository _repos;
private DbCommand _command; private DbCommand _command;
private string _paramPrefix; private string _paramPrefix;
private bool isLeftSide = true; private bool _isLeftSide = true;
protected bool _useAltName; protected bool _useAltName;
protected Dialect _dialect; protected Dialect _dialect;
protected StringBuilder _sb; protected StringBuilder _sb;
@ -67,12 +67,12 @@ namespace Marr.Data.QGen
{ {
_sb.Append("("); _sb.Append("(");
isLeftSide = true; _isLeftSide = true;
Visit(expression.Left); Visit(expression.Left);
_sb.AppendFormat(" {0} ", Decode(expression.NodeType)); _sb.AppendFormat(" {0} ", Decode(expression));
isLeftSide = false; _isLeftSide = false;
Visit(expression.Right); Visit(expression.Right);
_sb.Append(")"); _sb.Append(")");
@ -107,7 +107,7 @@ namespace Marr.Data.QGen
protected override Expression VisitMemberAccess(MemberExpression expression) protected override Expression VisitMemberAccess(MemberExpression expression)
{ {
if (isLeftSide) if (_isLeftSide)
{ {
string fqColumn = GetFullyQualifiedColumnName(expression.Member, expression.Expression.Type); string fqColumn = GetFullyQualifiedColumnName(expression.Member, expression.Expression.Type);
_sb.Append(fqColumn); _sb.Append(fqColumn);
@ -127,12 +127,20 @@ namespace Marr.Data.QGen
protected override Expression VisitConstant(ConstantExpression expression) protected override Expression VisitConstant(ConstantExpression expression)
{ {
// Add parameter to Command.Parameters if (expression.Value != null)
string paramName = string.Concat(_paramPrefix, "P", _command.Parameters.Count.ToString()); {
// Add parameter to Command.Parameters
string paramName = string.Concat(_paramPrefix, "P", _command.Parameters.Count.ToString());
_sb.Append(paramName); _sb.Append(paramName);
var parameter = new ParameterChainMethods(_command, paramName, expression.Value).Parameter;
}
else
{
_sb.Append("NULL");
}
var parameter = new ParameterChainMethods(_command, paramName, expression.Value).Parameter;
return expression; return expression;
} }
@ -182,12 +190,7 @@ namespace Marr.Data.QGen
} }
string columnName = DataHelper.GetColumnName(declaringType, member.Name, _useAltName); string columnName = DataHelper.GetColumnName(declaringType, member.Name, _useAltName);
return _dialect.CreateToken(string.Format("{0}.{1}", table.Alias, columnName));
if (!_useAltName)
return _dialect.CreateToken(string.Format("{0}.{1}", table.Alias, columnName));
else
return _dialect.CreateToken(string.Format("{0}", columnName));
} }
else else
{ {
@ -196,9 +199,22 @@ namespace Marr.Data.QGen
} }
} }
private string Decode(ExpressionType expType) private string Decode(BinaryExpression expression)
{ {
switch (expType) bool isRightSideNullConstant = expression.Right.NodeType ==
ExpressionType.Constant &&
((ConstantExpression)expression.Right).Value == null;
if (isRightSideNullConstant)
{
switch (expression.NodeType)
{
case ExpressionType.Equal: return "IS";
case ExpressionType.NotEqual: return "IS NOT";
}
}
switch (expression.NodeType)
{ {
case ExpressionType.AndAlso: return "AND"; case ExpressionType.AndAlso: return "AND";
case ExpressionType.And: return "AND"; case ExpressionType.And: return "AND";
@ -210,7 +226,7 @@ namespace Marr.Data.QGen
case ExpressionType.NotEqual: return "<>"; case ExpressionType.NotEqual: return "<>";
case ExpressionType.OrElse: return "OR"; case ExpressionType.OrElse: return "OR";
case ExpressionType.Or: return "OR"; case ExpressionType.Or: return "OR";
default: throw new NotSupportedException(string.Format("{0} statement is not supported", expType.ToString())); default: throw new NotSupportedException(string.Format("{0} statement is not supported", expression.NodeType.ToString()));
} }
} }
@ -223,7 +239,7 @@ namespace Marr.Data.QGen
MemberExpression memberExp = (body.Object as MemberExpression); MemberExpression memberExp = (body.Object as MemberExpression);
string fqColumn = GetFullyQualifiedColumnName(memberExp.Member, memberExp.Expression.Type); string fqColumn = GetFullyQualifiedColumnName(memberExp.Member, memberExp.Expression.Type);
_sb.AppendFormat("({0} LIKE '%' + {1} + '%')", fqColumn, paramName); _sb.AppendFormat(_dialect.ContainsFormat, fqColumn, paramName);
} }
private void Write_StartsWith(MethodCallExpression body) private void Write_StartsWith(MethodCallExpression body)
@ -235,7 +251,7 @@ namespace Marr.Data.QGen
MemberExpression memberExp = (body.Object as MemberExpression); MemberExpression memberExp = (body.Object as MemberExpression);
string fqColumn = GetFullyQualifiedColumnName(memberExp.Member, memberExp.Expression.Type); string fqColumn = GetFullyQualifiedColumnName(memberExp.Member, memberExp.Expression.Type);
_sb.AppendFormat("({0} LIKE {1} + '%')", fqColumn, paramName); _sb.AppendFormat(_dialect.StartsWithFormat, fqColumn, paramName);
} }
private void Write_EndsWith(MethodCallExpression body) private void Write_EndsWith(MethodCallExpression body)
@ -247,7 +263,7 @@ namespace Marr.Data.QGen
MemberExpression memberExp = (body.Object as MemberExpression); MemberExpression memberExp = (body.Object as MemberExpression);
string fqColumn = GetFullyQualifiedColumnName(memberExp.Member, memberExp.Expression.Type); string fqColumn = GetFullyQualifiedColumnName(memberExp.Member, memberExp.Expression.Type);
_sb.AppendFormat("({0} LIKE '%' + {1})", fqColumn, paramName); _sb.AppendFormat(_dialect.EndsWithFormat, fqColumn, paramName);
} }
/// <summary> /// <summary>

View File

@ -72,7 +72,7 @@ namespace Marr.Data.Reflection
} }
/// <summary> /// <summary>
/// Instantiantes a type using the FastReflector library for increased speed. /// Instantiantes a type using the Fasterflect library for increased speed.
/// </summary> /// </summary>
/// <param name="type"></param> /// <param name="type"></param>
/// <returns></returns> /// <returns></returns>

View File

@ -16,9 +16,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. */
using System; using System;
using System.Reflection; using System.Reflection;
// ReSharper disable CheckNamespace
namespace Marr.Data namespace Marr.Data
// ReSharper restore CheckNamespace
{ {
public class ReflectionHelper public class ReflectionHelper
{ {