From: <ste...@us...> - 2009-08-31 10:01:52
|
Revision: 4703 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4703&view=rev Author: steverstrong Date: 2009-08-31 10:01:43 +0000 (Mon, 31 Aug 2009) Log Message: ----------- New files for linq provider Added Paths: ----------- trunk/nhibernate/lib/net/3.5/Remotion.Data.Linq.dll trunk/nhibernate/lib/net/3.5/Remotion.Interfaces.dll trunk/nhibernate/lib/net/3.5/Remotion.dll trunk/nhibernate/src/NHibernate/Hql/Ast/HqlExpression.cs trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs trunk/nhibernate/src/NHibernate/Linq/CommandData.cs trunk/nhibernate/src/NHibernate/Linq/HqlNodeStack.cs trunk/nhibernate/src/NHibernate/Linq/NamedParameter.cs trunk/nhibernate/src/NHibernate/Linq/NhExpressionTreeVisitor.cs trunk/nhibernate/src/NHibernate/Linq/NhQueryExecutor.cs trunk/nhibernate/src/NHibernate/Linq/NhQueryable.cs trunk/nhibernate/src/NHibernate/Linq/Nominator.cs trunk/nhibernate/src/NHibernate/Linq/ParameterAggregator.cs trunk/nhibernate/src/NHibernate/Linq/ProjectionEvaluator.cs trunk/nhibernate/src/NHibernate/Linq/QueryModelVisitor.cs trunk/nhibernate/src/NHibernate/Linq/ResultTransformer.cs trunk/nhibernate/src/NHibernate.Test/Linq/LinqQuerySamples.cs trunk/nhibernate/src/NHibernate.Test/Linq/ReadonlyTestCase.cs Added: trunk/nhibernate/lib/net/3.5/Remotion.Data.Linq.dll =================================================================== (Binary files differ) Property changes on: trunk/nhibernate/lib/net/3.5/Remotion.Data.Linq.dll ___________________________________________________________________ Added: svn:executable + * Added: svn:mime-type + application/octet-stream Added: trunk/nhibernate/lib/net/3.5/Remotion.Interfaces.dll =================================================================== (Binary files differ) Property changes on: trunk/nhibernate/lib/net/3.5/Remotion.Interfaces.dll ___________________________________________________________________ Added: svn:executable + * Added: svn:mime-type + application/octet-stream Added: trunk/nhibernate/lib/net/3.5/Remotion.dll =================================================================== (Binary files differ) Property changes on: trunk/nhibernate/lib/net/3.5/Remotion.dll ___________________________________________________________________ Added: svn:executable + * Added: svn:mime-type + application/octet-stream Added: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlExpression.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlExpression.cs 2009-08-31 10:01:43 UTC (rev 4703) @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Reflection; +using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Hql.Ast.ANTLR.Tree; + +namespace NHibernate.Hql.Ast +{ + public class HqlExpression : IQueryExpression + { + private readonly IASTNode _node; + private readonly System.Type _type; + private readonly string _key; + + public HqlExpression(HqlQuery node, System.Type type) + { + _node = node.AstNode; + _type = type; + _key = _node.ToStringTree(); + } + + public IASTNode Translate(ISessionFactory sessionFactory) + { + return _node; + } + + public string Key + { + get { return _key; } + } + + public System.Type Type + { + get { return _type; } + } + } +} Property changes on: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlExpression.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs 2009-08-31 10:01:43 UTC (rev 4703) @@ -0,0 +1,332 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using NHibernate.Hql.Ast.ANTLR.Tree; + +namespace NHibernate.Hql.Ast +{ + public class HqlTreeBuilder + { + private readonly ASTFactory _factory; + + public HqlTreeBuilder() + { + _factory = new ASTFactory(new ASTTreeAdaptor()); + } + + public HqlQuery Query() + { + return new HqlQuery(_factory); + } + + public HqlQuery Query(HqlSelectFrom selectFrom) + { + return new HqlQuery(_factory, selectFrom); + } + + public HqlQuery Query(HqlSelectFrom selectFrom, HqlWhere where) + { + return new HqlQuery(_factory, selectFrom, where); + } + + public HqlTreeNode Query(HqlSelectFrom selectFrom, HqlWhere where, HqlOrderBy orderBy) + { + return new HqlQuery(_factory, selectFrom, where, orderBy); + } + + public HqlSelectFrom SelectFrom() + { + return new HqlSelectFrom(_factory); + } + + public HqlSelectFrom SelectFrom(HqlSelect select) + { + return new HqlSelectFrom(_factory, select); + } + + public HqlSelectFrom SelectFrom(HqlFrom @from, HqlSelect select) + { + return new HqlSelectFrom(_factory, @from, select); + } + + public HqlSelectFrom SelectFrom(HqlFrom @from) + { + return new HqlSelectFrom(_factory, @from); + } + + public HqlFrom From(HqlRange range) + { + return new HqlFrom(_factory, range); + } + + public HqlFrom From() + { + return new HqlFrom(_factory); + } + + public HqlRange Range(HqlIdent ident) + { + return new HqlRange(_factory, ident); + } + + public HqlRange Range() + { + return new HqlRange(_factory); + } + + public HqlRange Range(HqlTreeNode ident, HqlAlias alias) + { + return new HqlRange(_factory, ident, alias); + } + + public HqlIdent Ident(string ident) + { + return new HqlIdent(_factory, ident); + } + + public HqlAlias Alias(string alias) + { + return new HqlAlias(_factory, alias); + } + + public HqlEquality Equality() + { + return new HqlEquality(_factory); + } + + public HqlBooleanAnd BooleanAnd() + { + return new HqlBooleanAnd(_factory); + } + + public HqlBooleanOr BooleanOr() + { + return new HqlBooleanOr(_factory); + } + + public HqlAdd Add() + { + return new HqlAdd(_factory); + } + + public HqlSubtract Subtract() + { + return new HqlSubtract(_factory); + } + + public HqlMultiplty Multiply() + { + return new HqlMultiplty(_factory); + } + + public HqlDivide Divide() + { + return new HqlDivide(_factory); + } + + public HqlDot Dot() + { + return new HqlDot(_factory); + } + + public HqlParameter Parameter(string name) + { + return new HqlParameter(_factory, name); + } + + public HqlWhere Where(HqlTreeNode expression) + { + return new HqlWhere(_factory, expression); + } + + public HqlWhere Where() + { + return new HqlWhere(_factory); + } + + // TODO - constant will be removed when we have parameter handling done properly. Particularly bad datetime handling here, so it'll be good to delete it :) + public HqlConstant Constant(object value) + { + if (value == null) + { + return new HqlNull(_factory); + } + else + { + switch (System.Type.GetTypeCode(value.GetType())) + { + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + return new HqlIntegerConstant(_factory, value.ToString()); + case TypeCode.Single: + return new HqlFloatConstant(_factory, value.ToString()); + case TypeCode.Double: + return new HqlDoubleConstant(_factory, value.ToString()); + case TypeCode.Decimal: + return new HqlDecimalConstant(_factory, value.ToString()); + case TypeCode.String: + case TypeCode.Char: + return new HqlStringConstant(_factory, "\'" + value + "\'"); + case TypeCode.DateTime: + return new HqlStringConstant(_factory, "\'" + ((DateTime)value).ToString() + "\'"); + case TypeCode.Boolean: + return new HqlStringConstant(_factory, "\'" + (((bool)value) ? "true" : "false") + "\'"); + default: + throw new NotSupportedException(string.Format("The constant for '{0}' is not supported", value)); + } + } + } + + public HqlOrderBy OrderBy(HqlTreeNode expression, HqlDirection hqlDirection) + { + return new HqlOrderBy(_factory, expression, hqlDirection); + } + + public HqlSelect Select(HqlTreeNode expression) + { + return new HqlSelect(_factory, expression); + } + + public HqlSelect Select(params HqlTreeNode[] expression) + { + return new HqlSelect(_factory, expression); + } + + public HqlSelect Select(IEnumerable<HqlTreeNode> expressions) + { + return new HqlSelect(_factory, expressions.ToArray()); + } + + public HqlConstructor Constructor(ConstructorInfo constructor) + { + return new HqlConstructor(_factory, constructor); + } + + public HqlNill Holder() + { + return new HqlNill(_factory); + } + + public HqlCase Case() + { + return new HqlCase(_factory); + } + + public HqlWhen When() + { + return new HqlWhen(_factory); + } + + public HqlElse Else() + { + return new HqlElse(_factory); + } + + public HqlInequality Inequality() + { + return new HqlInequality(_factory); + } + + public HqlLessThan LessThan() + { + return new HqlLessThan(_factory); + } + + public HqlLessThanOrEqual LessThanOrEqual() + { + return new HqlLessThanOrEqual(_factory); + } + + public HqlGreaterThan GreaterThan() + { + return new HqlGreaterThan(_factory); + } + + public HqlGreaterThanOrEqual GreaterThanOrEqual() + { + return new HqlGreaterThanOrEqual(_factory); + } + + public HqlCount Count(HqlTreeNode child) + { + return new HqlCount(_factory, child); + } + + public HqlRowStar RowStar() + { + return new HqlRowStar(_factory); + } + + public HqlCast Cast(HqlTreeNode expression, System.Type type) + { + return new HqlCast(_factory, expression, type); + } + + public HqlBitwiseNot BitwiseNot() + { + return new HqlBitwiseNot(_factory); + } + + public HqlNot Not() + { + return new HqlNot(_factory); + } + + public HqlAverage Average() + { + return new HqlAverage(_factory); + } + + public HqlAverage Average(HqlTreeNode expression) + { + return new HqlAverage(_factory, expression); + } + + public HqlSum Sum() + { + return new HqlSum(_factory); + } + + public HqlSum Sum(HqlTreeNode expression) + { + return new HqlSum(_factory, expression); + } + + public HqlMin Min() + { + return new HqlMin(_factory); + } + + public HqlMax Max() + { + return new HqlMax(_factory); + } + + public HqlAnd And(HqlTreeNode left, HqlTreeNode right) + { + return new HqlAnd(_factory, left, right); + } + + public HqlJoin Join(HqlTreeNode expression, HqlAlias @alias) + { + return new HqlJoin(_factory, expression, @alias); + } + + public HqlAny Any() + { + return new HqlAny(_factory); + } + + public HqlExists Exists() + { + return new HqlExists(_factory); + } + + public HqlElements Elements() + { + return new HqlElements(_factory); + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs 2009-08-31 10:01:43 UTC (rev 4703) @@ -0,0 +1,566 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Hql.Ast.ANTLR.Tree; + +namespace NHibernate.Hql.Ast +{ + public class HqlTreeNode + { + protected readonly IASTNode _node; + protected readonly List<HqlTreeNode> _children; + + protected HqlTreeNode(int type, string text, IASTFactory factory, params HqlTreeNode[] children) + { + _node = factory.CreateNode(type, text); + _children = new List<HqlTreeNode>(); + + foreach (var child in children) + { + _children.Add(child); + _node.AddChild(child.AstNode); + } + } + + public IEnumerable<HqlTreeNode> NodesPreOrder + { + get + { + yield return this; + + foreach (var child in _children) + { + foreach (var node in child.NodesPreOrder) + { + yield return node; + } + } + } + } + + public IEnumerable<HqlTreeNode> NodesPostOrder + { + get + { + foreach (var child in _children) + { + foreach (var node in child.NodesPostOrder) + { + yield return node; + } + } + + yield return this; + } + } + + public IEnumerable<HqlTreeNode> Children + { + get + { + foreach (var child in _children) + { + yield return child; + } + } + } + + public void ClearChildren() + { + _children.Clear(); + _node.ClearChildren(); + } + + internal IASTNode AstNode + { + get { return _node; } + } + + internal void AddChild(HqlTreeNode child) + { + _children.Add(child); + _node.AddChild(child.AstNode); + } + } + + public class HqlQuery : HqlTreeNode + { + internal HqlQuery(IASTFactory factory, params HqlTreeNode[] children) + : base(HqlSqlWalker.QUERY, "query", factory, children) + { + } + } + + + public class HqlIdent : HqlTreeNode + { + internal HqlIdent(IASTFactory factory, string ident) + : base(HqlSqlWalker.IDENT, ident, factory) + { + } + } + + public class HqlRange : HqlTreeNode + { + internal HqlRange(IASTFactory factory, params HqlTreeNode[] children) + : base(HqlSqlWalker.RANGE, "range", factory, children) + { + } + } + + public class HqlFrom : HqlTreeNode + { + internal HqlFrom(IASTFactory factory, params HqlTreeNode[] children) + : base(HqlSqlWalker.FROM, "from", factory, children) + { + } + } + + public class HqlSelectFrom : HqlTreeNode + { + internal HqlSelectFrom(IASTFactory factory, params HqlTreeNode[] children) + : base(HqlSqlWalker.SELECT_FROM, "select_from", factory, children) + { + } + } + + public class HqlAlias : HqlTreeNode + { + public HqlAlias(IASTFactory factory, string @alias) + : base(HqlSqlWalker.ALIAS, alias, factory) + { + } + } + + public class HqlDivide : HqlTreeNode + { + public HqlDivide(IASTFactory factory) + : base(HqlSqlWalker.DIV, "/", factory) + { + } + } + + public class HqlMultiplty : HqlTreeNode + { + public HqlMultiplty(IASTFactory factory) + : base(HqlSqlWalker.STAR, "*", factory) + { + } + } + + public class HqlSubtract : HqlTreeNode + { + public HqlSubtract(IASTFactory factory) + : base(HqlSqlWalker.MINUS, "-", factory) + { + } + } + + public class HqlAdd : HqlTreeNode + { + public HqlAdd(IASTFactory factory) + : base(HqlSqlWalker.PLUS, "+", factory) + { + } + } + + public class HqlBooleanOr : HqlTreeNode + { + public HqlBooleanOr(IASTFactory factory) + : base(HqlSqlWalker.OR, "or", factory) + { + } + } + + public class HqlBooleanAnd : HqlTreeNode + { + public HqlBooleanAnd(IASTFactory factory) + : base(HqlSqlWalker.AND, "/", factory) + { + } + } + + public class HqlEquality : HqlTreeNode + { + public HqlEquality(IASTFactory factory) + : base(HqlSqlWalker.EQ, "==", factory) + { + } + } + + public class HqlParameter : HqlTreeNode + { + public HqlParameter(IASTFactory factory, string name) + : base(HqlSqlWalker.PARAM, name, factory) + { + } + } + + public class HqlDot : HqlTreeNode + { + public HqlDot(IASTFactory factory) + : base(HqlSqlWalker.DOT, ".", factory) + { + } + } + + public class HqlWhere : HqlTreeNode + { + public HqlWhere(IASTFactory factory) + : base(HqlSqlWalker.WHERE, "where", factory) + { + } + + public HqlWhere(IASTFactory factory, HqlTreeNode expression) + : base(HqlSqlWalker.WHERE, "where", factory, expression) + { + } + } + + public class HqlConstant : HqlTreeNode + { + public HqlConstant(IASTFactory factory, int type, string value) + : base(type, value, factory) + { + } + } + + public class HqlStringConstant : HqlConstant + { + public HqlStringConstant(IASTFactory factory, string s) + : base(factory, HqlSqlWalker.QUOTED_String, s) + { + } + } + + public class HqlDoubleConstant : HqlConstant + { + public HqlDoubleConstant(IASTFactory factory, string s) + : base(factory, HqlSqlWalker.NUM_DOUBLE, s) + { + } + } + + public class HqlFloatConstant : HqlConstant + { + public HqlFloatConstant(IASTFactory factory, string s) + : base(factory, HqlSqlWalker.NUM_FLOAT, s) + { + } + } + + public class HqlIntegerConstant : HqlConstant + { + public HqlIntegerConstant(IASTFactory factory, string s) + : base(factory, HqlSqlWalker.NUM_INT, s) + { + } + } + + public class HqlDecimalConstant : HqlConstant + { + public HqlDecimalConstant(IASTFactory factory, string s) + : base(factory, HqlSqlWalker.NUM_DECIMAL, s) + { + } + } + + public class HqlNull : HqlConstant + { + public HqlNull(IASTFactory factory) + : base(factory, HqlSqlWalker.NULL, "null") + { + } + } + + public class HqlOrderBy : HqlTreeNode + { + public HqlOrderBy(IASTFactory factory, HqlTreeNode expression, HqlDirection hqlDirection) + : base(HqlSqlWalker.ORDER, "", factory, expression, + hqlDirection == HqlDirection.Ascending ? + (HqlTreeNode)new HqlDirectionAscending(factory) : (HqlTreeNode)new HqlDirectionDescending(factory)) + { + } + } + + public enum HqlDirection + { + Ascending, + Descending + } + + public class HqlDirectionAscending : HqlTreeNode + { + public HqlDirectionAscending(IASTFactory factory) + : base(HqlSqlWalker.ASCENDING, "asc", factory) + { + } + } + + public class HqlDirectionDescending : HqlTreeNode + { + public HqlDirectionDescending(IASTFactory factory) + : base(HqlSqlWalker.DESCENDING, "desc", factory) + { + } + } + + public class HqlSelect : HqlTreeNode + { + public HqlSelect(IASTFactory factory, params HqlTreeNode[] expression) + : base(HqlSqlWalker.SELECT, "select", factory, expression) + { + } + } + + public class HqlConstructor : HqlTreeNode + { + public HqlConstructor(IASTFactory factory, ConstructorInfo ctor) + : base(HqlSqlWalker.CONSTRUCTOR, "ctor", factory) + { + ((ASTNode)_node).Hack = ctor; + } + } + + public class HqlNill : HqlTreeNode + { + public HqlNill(IASTFactory factory) + : base(0, "nill", factory) + { + } + } + + public class HqlElse : HqlTreeNode + { + public HqlElse(IASTFactory factory) + : base(HqlSqlWalker.ELSE, "else", factory) + { + } + } + + public class HqlWhen : HqlTreeNode + { + public HqlWhen(IASTFactory factory) + : base(HqlSqlWalker.WHEN, "when", factory) + { + } + } + + public class HqlCase : HqlTreeNode + { + public HqlCase(IASTFactory factory) + : base(HqlSqlWalker.CASE, "case", factory) + { + } + } + + public class HqlGreaterThanOrEqual : HqlTreeNode + { + public HqlGreaterThanOrEqual(IASTFactory factory) + : base(HqlSqlWalker.GE, "ge", factory) + { + } + } + + public class HqlGreaterThan : HqlTreeNode + { + public HqlGreaterThan(IASTFactory factory) + : base(HqlSqlWalker.GT, "gt", factory) + { + } + } + + public class HqlLessThanOrEqual : HqlTreeNode + { + public HqlLessThanOrEqual(IASTFactory factory) + : base(HqlSqlWalker.LE, "le", factory) + { + } + } + + public class HqlLessThan : HqlTreeNode + { + public HqlLessThan(IASTFactory factory) + : base(HqlSqlWalker.LT, "lt", factory) + { + } + } + + public class HqlInequality : HqlTreeNode + { + public HqlInequality(IASTFactory factory) + : base(HqlSqlWalker.NE, "ne", factory) + { + } + } + + public class HqlRowStar : HqlTreeNode + { + public HqlRowStar(IASTFactory factory) + : base(HqlSqlWalker.ROW_STAR, "*", factory) + { + } + } + + public class HqlCount : HqlTreeNode + { + public HqlCount(IASTFactory factory, HqlTreeNode child) + : base(HqlSqlWalker.COUNT, "count", factory, child) + { + } + } + + public class HqlAs : HqlTreeNode + { + public HqlAs(IASTFactory factory, HqlTreeNode expression, System.Type type) : base(HqlSqlWalker.AS, "as", factory, expression) + { + switch (System.Type.GetTypeCode(type)) + { + case TypeCode.Int32: + AddChild(new HqlIdent(factory, "integer")); + break; + default: + throw new InvalidOperationException(); + } + } + } + + public class HqlCast : HqlTreeNode + { + public HqlCast(IASTFactory factory, HqlTreeNode expression, System.Type type) : base(HqlSqlWalker.METHOD_CALL, "method", factory) + { + HqlIdent typeIdent; + + if (IsNullableType(type)) + { + type = ExtractUnderlyingTypeFromNullable(type); + } + + switch (System.Type.GetTypeCode(type)) + { + case TypeCode.Int32: + typeIdent = new HqlIdent(factory, "integer"); + break; + case TypeCode.Decimal: + typeIdent = new HqlIdent(factory, "decimal"); + break; + case TypeCode.DateTime: + typeIdent = new HqlIdent(factory, "datetime"); + break; + default: + throw new NotSupportedException(string.Format("Don't currently support casts to {0}", type.Name)); + } + + AddChild(new HqlIdent(factory, "cast")); + AddChild(new HqlExpressionList(factory, expression, typeIdent)); + } + + private static System.Type ExtractUnderlyingTypeFromNullable(System.Type type) + { + return type.GetGenericArguments()[0]; + } + + private static bool IsNullableType(System.Type type) + { + return (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); + } + } + + public class HqlExpressionList : HqlTreeNode + { + public HqlExpressionList(IASTFactory factory, params HqlTreeNode[] expression) : base(HqlSqlWalker.EXPR_LIST, "expr_list", factory, expression) + { + } + } + + public class HqlNot : HqlTreeNode + { + public HqlNot(IASTFactory factory) : base(HqlSqlWalker.NOT, "not", factory) + { + } + } + + public class HqlAverage : HqlTreeNode + { + public HqlAverage(IASTFactory factory) + : base(HqlSqlWalker.AGGREGATE, "avg", factory) + { + } + + public HqlAverage(IASTFactory factory, HqlTreeNode expression) : base(HqlSqlWalker.AGGREGATE, "avg", factory, expression) + { + } + } + + public class HqlBitwiseNot : HqlTreeNode + { + public HqlBitwiseNot(IASTFactory factory) : base(HqlSqlWalker.BNOT, "not", factory) + { + } + } + + public class HqlSum : HqlTreeNode + { + public HqlSum(IASTFactory factory) + : base(HqlSqlWalker.AGGREGATE, "sum", factory) + { + } + + public HqlSum(IASTFactory factory, HqlTreeNode expression) + : base(HqlSqlWalker.AGGREGATE, "sum", factory, expression) + { + } + } + + public class HqlMax : HqlTreeNode + { + public HqlMax(IASTFactory factory) : base(HqlSqlWalker.AGGREGATE, "max", factory) + { + } + } + + public class HqlMin : HqlTreeNode + { + public HqlMin(IASTFactory factory) + : base(HqlSqlWalker.AGGREGATE, "min", factory) + { + } + } + + public class HqlAnd : HqlTreeNode + { + public HqlAnd(IASTFactory factory, HqlTreeNode left, HqlTreeNode right) : base(HqlSqlWalker.AND, "and", factory, left, right) + { + } + } + + public class HqlJoin : HqlTreeNode + { + public HqlJoin(IASTFactory factory, HqlTreeNode expression, HqlAlias @alias) : base(HqlSqlWalker.JOIN, "join", factory, expression, @alias) + { + } + } + + public class HqlAny : HqlTreeNode + { + public HqlAny(IASTFactory factory) : base(HqlSqlWalker.ANY, "any", factory) + { + } + } + + public class HqlExists : HqlTreeNode + { + public HqlExists(IASTFactory factory) : base(HqlSqlWalker.EXISTS, "exists", factory) + { + } + } + + public class HqlElements : HqlTreeNode + { + public HqlElements(IASTFactory factory) : base(HqlSqlWalker.ELEMENTS, "elements", factory) + { + } + } + +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate/Linq/CommandData.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/CommandData.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/CommandData.cs 2009-08-31 10:01:43 UTC (rev 4703) @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using NHibernate.Hql.Ast; + +namespace NHibernate.Linq +{ + public class CommandData + { + public CommandData(HqlQuery statement, NamedParameter[] namedParameters, LambdaExpression projectionExpression, List<Action<IQuery>> additionalCriteria) + { + Statement = statement; + NamedParameters = namedParameters; + ProjectionExpression = projectionExpression; + AdditionalCriteria = additionalCriteria; + } + + public HqlQuery Statement { get; private set; } + public NamedParameter[] NamedParameters { get; private set; } + public LambdaExpression ProjectionExpression { get; set; } + public List<Action<IQuery>> AdditionalCriteria { get; set; } + + public IQuery CreateQuery(ISession session, System.Type type) + { + var query = session.CreateQuery(new HqlExpression(Statement, type)); + + foreach (var parameter in NamedParameters) + query.SetParameter(parameter.Name, parameter.Value); + + if (ProjectionExpression != null) + { + query.SetResultTransformer(new ResultTransformer(ProjectionExpression)); + } + + foreach (var criteria in AdditionalCriteria) + { + criteria(query); + } + + return query; + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/HqlNodeStack.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/HqlNodeStack.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/HqlNodeStack.cs 2009-08-31 10:01:43 UTC (rev 4703) @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using NHibernate.Hql.Ast; + +namespace NHibernate.Linq +{ + public class HqlNodeStack + { + private readonly Stack<HqlTreeNode> _stack = new Stack<HqlTreeNode>(); + private readonly HqlNill _root; + + public HqlNodeStack(HqlTreeBuilder builder) + { + _root = builder.Holder(); + _stack.Push(_root); + } + + public IEnumerable<HqlTreeNode> NodesPreOrder + { + get { return _root.NodesPreOrder; } + } + + public IEnumerable<HqlTreeNode> Finish() + { + var holder = (HqlNill) _stack.Pop(); + + return holder.Children; + } + + public void PushAndPop(HqlTreeNode query) + { + Push(query).Dispose(); + } + + public IDisposable Push(HqlTreeNode query) + { + _stack.Peek().AddChild(query); + + _stack.Push(query); + + var stackEntry = new HqlNodeStackEntry(this, query); + + return stackEntry; + } + + private HqlTreeNode Peek() + { + return _stack.Peek(); + } + + private void Pop() + { + _stack.Pop(); + } + + public class HqlNodeStackEntry : IDisposable + { + private readonly HqlNodeStack _parent; + private readonly HqlTreeNode _node; + + internal HqlNodeStackEntry(HqlNodeStack parent, HqlTreeNode node) + { + _parent = parent; + _node = node; + } + + public void Dispose() + { + if (_parent.Peek() != _node) + { + throw new InvalidOperationException(); + } + + _parent.Pop(); + } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/NamedParameter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/NamedParameter.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/NamedParameter.cs 2009-08-31 10:01:43 UTC (rev 4703) @@ -0,0 +1,14 @@ +namespace NHibernate.Linq +{ + public class NamedParameter + { + public NamedParameter(string name, object value) + { + Name = name; + Value = value; + } + + public string Name { get; set; } + public object Value { get; set; } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/NhExpressionTreeVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/NhExpressionTreeVisitor.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/NhExpressionTreeVisitor.cs 2009-08-31 10:01:43 UTC (rev 4703) @@ -0,0 +1,286 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using NHibernate.Hql.Ast; +using Remotion.Data.Linq.Clauses.Expressions; +using Remotion.Data.Linq.Clauses.ExpressionTreeVisitors; +using Remotion.Data.Linq.Parsing; + +namespace NHibernate.Linq +{ + public class NhExpressionTreeVisitor : ThrowingExpressionTreeVisitor + { + protected readonly HqlTreeBuilder _hqlTreeBuilder; + protected readonly HqlNodeStack _stack; + private readonly ParameterAggregator _parameterAggregator; + + public NhExpressionTreeVisitor(ParameterAggregator parameterAggregator) + { + _parameterAggregator = parameterAggregator; + _hqlTreeBuilder = new HqlTreeBuilder(); + _stack = new HqlNodeStack(_hqlTreeBuilder); + } + + public IEnumerable<HqlTreeNode> GetAstBuilderNode() + { + return _stack.Finish(); + } + + public virtual void Visit(Expression expression) + { + VisitExpression(expression); + } + + protected override Expression VisitQuerySourceReferenceExpression(QuerySourceReferenceExpression expression) + { + _stack.PushAndPop(_hqlTreeBuilder.Ident(expression.ReferencedQuerySource.ItemName)); + + return expression; + } + + protected override Expression VisitBinaryExpression(BinaryExpression expression) + { + HqlTreeNode operatorNode = GetHqlOperatorNodeForBinaryOperator(expression); + + using (_stack.Push(operatorNode)) + { + VisitExpression(expression.Left); + + VisitExpression(expression.Right); + } + + return expression; + } + + private HqlTreeNode GetHqlOperatorNodeForBinaryOperator(BinaryExpression expression) + { + switch (expression.NodeType) + { + case ExpressionType.Equal: + return _hqlTreeBuilder.Equality(); + + case ExpressionType.NotEqual: + return _hqlTreeBuilder.Inequality(); + + case ExpressionType.And: + case ExpressionType.AndAlso: + return _hqlTreeBuilder.BooleanAnd(); + + case ExpressionType.Or: + case ExpressionType.OrElse: + return _hqlTreeBuilder.BooleanOr(); + + case ExpressionType.Add: + return _hqlTreeBuilder.Add(); + + case ExpressionType.Subtract: + return _hqlTreeBuilder.Subtract(); + + case ExpressionType.Multiply: + return _hqlTreeBuilder.Multiply(); + + case ExpressionType.Divide: + return _hqlTreeBuilder.Divide(); + + case ExpressionType.LessThan: + return _hqlTreeBuilder.LessThan(); + + case ExpressionType.LessThanOrEqual: + return _hqlTreeBuilder.LessThanOrEqual(); + + case ExpressionType.GreaterThan: + return _hqlTreeBuilder.GreaterThan(); + + case ExpressionType.GreaterThanOrEqual: + return _hqlTreeBuilder.GreaterThanOrEqual(); + } + + throw new InvalidOperationException(); + } + + protected override Expression VisitUnaryExpression(UnaryExpression expression) + { + HqlTreeNode operatorNode = GetHqlOperatorNodeforUnaryOperator(expression); + + using (_stack.Push(operatorNode)) + { + VisitExpression(expression.Operand); + } + + return expression; + } + + private HqlTreeNode GetHqlOperatorNodeforUnaryOperator(UnaryExpression expression) + { + switch (expression.NodeType) + { + case ExpressionType.Not: + return _hqlTreeBuilder.Not(); + } + + throw new InvalidOperationException(); + } + + protected override Expression VisitMemberExpression(MemberExpression expression) + { + using (_stack.Push(_hqlTreeBuilder.Dot())) + { + Expression newExpression = VisitExpression(expression.Expression); + + _stack.PushAndPop(_hqlTreeBuilder.Ident(expression.Member.Name)); + + if (newExpression != expression.Expression) + { + return Expression.MakeMemberAccess(newExpression, expression.Member); + } + } + + return expression; + } + + protected override Expression VisitConstantExpression(ConstantExpression expression) + { + if (expression.Value != null) + { + System.Type t = expression.Value.GetType(); + + if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof (NhQueryable<>)) + { + _stack.PushAndPop(_hqlTreeBuilder.Ident(t.GetGenericArguments()[0].Name)); + return expression; + } + } + + /* + var namedParameter = _parameterAggregator.AddParameter(expression.Value); + + _expression = _hqlTreeBuilder.Parameter(namedParameter.Name); + + return expression; + */ + // TODO - get parameter support in place in the HQLQueryPlan + _stack.PushAndPop(_hqlTreeBuilder.Constant(expression.Value)); + + return expression; + } + + protected override Expression VisitMethodCallExpression(MethodCallExpression expression) + { + if (expression.Method.DeclaringType == typeof(Enumerable)) + { + switch (expression.Method.Name) + { + case "Any": + // Any has one or two arguments. Arg 1 is the source and arg 2 is the optional predicate + using (_stack.Push(_hqlTreeBuilder.Exists())) + { + using (_stack.Push(_hqlTreeBuilder.Query())) + { + using (_stack.Push(_hqlTreeBuilder.SelectFrom())) + { + using (_stack.Push(_hqlTreeBuilder.From())) + { + using (_stack.Push(_hqlTreeBuilder.Range())) + { + VisitExpression(expression.Arguments[0]); + + if (expression.Arguments.Count > 1) + { + var expr = (LambdaExpression) expression.Arguments[1]; + _stack.PushAndPop(_hqlTreeBuilder.Alias(expr.Parameters[0].Name)); + } + } + } + } + if (expression.Arguments.Count > 1) + { + using (_stack.Push(_hqlTreeBuilder.Where())) + { + VisitExpression(expression.Arguments[1]); + } + } + } + } + break; + default: + throw new NotSupportedException(string.Format("The Enumerable method {0} is not supported", expression.Method.Name)); + } + + return expression; + } + else + { + return base.VisitMethodCallExpression(expression); // throws + } + } + + protected override Expression VisitLambdaExpression(LambdaExpression expression) + { + VisitExpression(expression.Body); + + return expression; + } + + protected override Expression VisitParameterExpression(ParameterExpression expression) + { + _stack.PushAndPop(_hqlTreeBuilder.Ident(expression.Name)); + + return expression; + } + + protected override Expression VisitConditionalExpression(ConditionalExpression expression) + { + using (_stack.Push(_hqlTreeBuilder.Case())) + { + using (_stack.Push(_hqlTreeBuilder.When())) + { + VisitExpression(expression.Test); + + VisitExpression(expression.IfTrue); + } + + if (expression.IfFalse != null) + { + using (_stack.Push(_hqlTreeBuilder.Else())) + { + VisitExpression(expression.IfFalse); + } + } + } + + return expression; + } + + protected override Expression VisitSubQueryExpression(SubQueryExpression expression) + { + CommandData query = QueryModelVisitor.GenerateHqlQuery(expression.QueryModel, _parameterAggregator); + + if (query.ProjectionExpression != null) + { + throw new InvalidOperationException(); + } + + // TODO - what if there was a projection expression? + + _stack.PushAndPop(query.Statement); + + return expression; + } + + + // Called when a LINQ expression type is not handled above. + protected override Exception CreateUnhandledItemException<T>(T unhandledItem, string visitMethod) + { + string itemText = FormatUnhandledItem(unhandledItem); + var message = string.Format("The expression '{0}' (type: {1}) is not supported by this LINQ provider.", itemText, typeof(T)); + return new NotSupportedException(message); + } + + private string FormatUnhandledItem<T>(T unhandledItem) + { + var itemAsExpression = unhandledItem as Expression; + return itemAsExpression != null ? FormattingExpressionTreeVisitor.Format(itemAsExpression) : unhandledItem.ToString(); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/NhQueryExecutor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/NhQueryExecutor.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/NhQueryExecutor.cs 2009-08-31 10:01:43 UTC (rev 4703) @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Linq; +using Remotion.Data.Linq; + +namespace NHibernate.Linq +{ + public class NhQueryExecutor : IQueryExecutor + { + private readonly ISession _session; + + public NhQueryExecutor(ISession session) + { + _session = session; + } + + // Executes a query with a scalar result, i.e. a query that ends with a result operator such as Count, Sum, or Average. + public T ExecuteScalar<T>(QueryModel queryModel) + { + return ExecuteCollection<T>(queryModel).Single(); + } + + // Executes a query with a single result object, i.e. a query that ends with a result operator such as First, Last, Single, Min, or Max. + public T ExecuteSingle<T>(QueryModel queryModel, bool returnDefaultWhenEmpty) + { + return returnDefaultWhenEmpty ? ExecuteCollection<T>(queryModel).SingleOrDefault() : ExecuteCollection<T>(queryModel).Single(); + } + + // Executes a query with a collection result. + public IEnumerable<T> ExecuteCollection<T>(QueryModel queryModel) + { + var commandData = QueryModelVisitor.GenerateHqlQuery(queryModel); + + var query = commandData.CreateQuery(_session, typeof(T)); + + // TODO - check which call on Query makes most sense... + return (IEnumerable<T>) query.List(); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/NhQueryable.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/NhQueryable.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/NhQueryable.cs 2009-08-31 10:01:43 UTC (rev 4703) @@ -0,0 +1,29 @@ +using System.Linq; +using System.Linq.Expressions; +using Remotion.Data.Linq; + +namespace NHibernate.Linq +{ + /// <summary> + /// Provides the main entry point to a LINQ query. + /// </summary> + public class NhQueryable<T> : QueryableBase<T> + { + private static IQueryExecutor CreateExecutor(ISession session) + { + return new NhQueryExecutor(session); + } + + // This constructor is called by our users, create a new IQueryExecutor. + public NhQueryable(ISession session) + : base(CreateExecutor(session)) + { + } + + // This constructor is called indirectly by LINQ's query methods, just pass to base. + public NhQueryable(IQueryProvider provider, Expression expression) + : base(provider, expression) + { + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Nominator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Nominator.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Nominator.cs 2009-08-31 10:01:43 UTC (rev 4703) @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using Remotion.Data.Linq.Parsing; + +namespace NHibernate.Linq +{ + /// <summary> + /// Performs bottom-up analysis to determine which nodes that match a certain predicate + /// </summary> + class Nominator : ExpressionTreeVisitor + { + readonly Func<Expression, bool> _fnIsCandidate; + HashSet<Expression> _candidates; + bool _cannotBeCandidate; + + internal Nominator(Func<Expression, bool> fnIsCandidate) + { + _fnIsCandidate = fnIsCandidate; + } + + internal HashSet<Expression> Nominate(Expression expression) + { + _candidates = new HashSet<Expression>(); + VisitExpression(expression); + return _candidates; + } + + protected override Expression VisitExpression(Expression expression) + { + if (expression != null) + { + bool saveCannotBeEvaluated = _cannotBeCandidate; + _cannotBeCandidate = false; + + base.VisitExpression(expression); + + if (!_cannotBeCandidate) + { + if (_fnIsCandidate(expression)) + { + _candidates.Add(expression); + } + else + { + _cannotBeCandidate = true; + } + } + + _cannotBeCandidate |= saveCannotBeEvaluated; + } + + return expression; + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/ParameterAggregator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/ParameterAggregator.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/ParameterAggregator.cs 2009-08-31 10:01:43 UTC (rev 4703) @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace NHibernate.Linq +{ + public class ParameterAggregator + { + private readonly List<NamedParameter> _parameters = new List<NamedParameter>(); + + public NamedParameter AddParameter(object value) + { + var parameter = new NamedParameter("p" + (_parameters.Count + 1), value); + _parameters.Add(parameter); + return parameter; + } + + public NamedParameter[] GetParameters() + { + return _parameters.ToArray(); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/ProjectionEvaluator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/ProjectionEvaluator.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/ProjectionEvaluator.cs 2009-08-31 10:01:43 UTC (rev 4703) @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using System.Linq.Expressions; +using NHibernate.Hql.Ast; +using Remotion.Data.Linq.Parsing; + +namespace NHibernate.Linq +{ + public class ProjectionEvaluator : ExpressionTreeVisitor + { + protected readonly HqlTreeBuilder _hqlTreeBuilder; + protected readonly HqlNodeStack _stack; + private readonly ParameterAggregator _parameterAggregator; + private HashSet<Expression> _hqlNodes; + private readonly ParameterExpression _objectArray; + private Expression _projectionExpression; + private int _iColumn; + + public ProjectionEvaluator(ParameterAggregator parameterAggregator, ParameterExpression objectArray) + { + _parameterAggregator = parameterAggregator; + _objectArray = objectArray; + _hqlTreeBuilder = new HqlTreeBuilder(); + _stack = new HqlNodeStack(_hqlTreeBuilder); + } + + public Expression ProjectionExpression + { + get { return _projectionExpression; } + } + + public IEnumerable<HqlTreeNode> GetAstBuilderNode() + { + return _stack.Finish(); + } + + public void Visit(Expression expression) + { + // First, find the sub trees that can be expressed purely in HQL + _hqlNodes = new Nominator(CanBeEvaluatedInHql).Nominate(expression); + + // Now visit the tree + Expression projection = VisitExpression(expression); + + if ((projection != expression) && !_hqlNodes.Contains(expression)) + { + _projectionExpression = projection; + } + } + + protected override Expression VisitExpression(Expression expression) + { + if (expression == null) + { + return null; + } + + if (_hqlNodes.Contains(expression)) + { + // Pure HQL evaluation + var hqlVisitor = new NhExpressionTreeVisitor(_parameterAggregator); + hqlVisitor.Visit(expression); + hqlVisitor.GetAstBuilderNode().ForEach(n =>_stack.PushAndPop(n) ); + + return Expression.Convert(Expression.ArrayIndex(_objectArray, Expression.Constant(_iColumn++)), + expression.Type); + } + + // Can't handle this node with HQL. Just recurse down, and emit the expression + return base.VisitExpression(expression); + } + + private static bool CanBeEvaluatedInHql(Expression expression) + { + return (expression.NodeType != ExpressionType.MemberInit) && (expression.NodeType != ExpressionType.New); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/QueryModelVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/QueryModelVisitor.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/QueryModelVisitor.cs 2009-08-31 10:01:43 UTC (rev 4703) @@ -0,0 +1,309 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using NHibernate.Hql.Ast; +using Remotion.Data.Linq; +using Remotion.Data.Linq.Clauses; +using Remotion.Data.Linq.Clauses.Expressions; +using Remotion.Data.Linq.Clauses.ResultOperators; +using Remotion.Data.Linq.Clauses.StreamedData; +using Remotion.Data.Linq.Transformations; + +namespace NHibernate.Linq +{ + public class QueryModelVisitor : QueryModelVisitorBase + { + public static CommandData GenerateHqlQuery(QueryModel queryModel) + { + return GenerateHqlQuery(queryModel, new ParameterAggregator()); + } + + public static CommandData GenerateHqlQuery(QueryModel queryModel, ParameterAggregator aggregator) + { + // SubQueryFromClauseFlattener flattener = new SubQueryFromClauseFlattener(); + // flattener.VisitQueryModel(queryModel); + + var visitor = new QueryModelVisitor(aggregator); + visitor.VisitQueryModel(queryModel); + return visitor.GetHqlCommand(); + } + + private readonly HqlTreeBuilder _hqlTreeBuilder; + private readonly ParameterAggregator _parameterAggregator; + private readonly ParameterExpression _objectArray; + private Expression _projectionExpression; + private IStreamedDataInfo _inputInfo; + readonly List<Action<IQuery>> _additionalCriteria = new List<Action<IQuery>>(); + + + private HqlWhere _whereClause; + private HqlSelect _selectClause; + private HqlFrom _fromClause; + private readonly List<HqlTreeNode> _orderByClauses = new List<HqlTreeNode>(); + + private QueryModelVisitor(ParameterAggregator parameterAggregator) + { + _hqlTreeBuilder = new HqlTreeBuilder(); + _parameterAggregator = parameterAggregator; + _objectArray = Expression.Parameter(typeof (object[]), "objectArray"); + } + + public CommandData GetHqlCommand() + { + HqlSelectFrom selectFrom = _hqlTreeBuilder.SelectFrom(); + + if (_fromClause != null) + { + selectFrom.AddChild(_fromClause); + } + + if (_selectClause != null) + { + selectFrom.AddChild(_selectClause); + } + + HqlQuery query = _hqlTreeBuilder.Query(selectFrom); + + if (_whereClause != null) + { + query.AddChild(_whereClause); + } + + foreach (var orderByClause in _orderByClauses) + { + query.AddChild(orderByClause); + } + + return new CommandData(query, + _parameterAggregator.GetParameters(), + _projectionExpression == null ? null : Expression.Lambda(_projectionExpression, _objectArray), + _additionalCriteria); + } + + public override void VisitQueryModel(QueryModel queryModel) + { + if (queryModel.MainFromClause != null) + { + queryModel.MainFromClause.Accept(this, queryModel); + } + + if (queryModel.SelectClause != null) + { + queryModel.SelectClause.Accept(this, queryModel); + } + + VisitBodyClauses(queryModel.BodyClauses, queryModel); + + VisitResultOperators(queryModel.ResultOperators, queryModel); + } + + public override void VisitMainFromClause(MainFromClause fromClause, QueryModel queryModel) + { + var visitor = new NhExpressionTreeVisitor(_parameterAggregator); + visitor.Visit(fromClause.FromExpression); + + _fromClause = _hqlTreeBuilder.From( + _hqlTreeBuilder.Range( + visitor.GetAstBuilderNode().Single(), + _hqlTreeBuilder.Alias(fromClause.ItemName))); + + base.VisitMainFromClause(fromClause, queryModel); + } + + + public override void VisitResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, int index) + { + if (IsCountOperator(resultOperator)) + { + ProcessCountOperator(resultOperator); + } + else if (IsAggregateOperator(resultOperator)) + { + ProcessAggregateOperator(resultOperator); + } + else if (IsPositionalOperator(resultOperator)) + { + ProcessPositionalOperator(resultOperator); + } + else + { + throw new NotSupportedException(string.Format("The {0} result operator is not current supported", + resultOperator.GetType().Name)); + } + + base.VisitResultOperator(resultOperator, queryModel, index); + } + + private void ProcessPositionalOperator(ResultOperatorBase resultOperator) + { + var first = (FirstResultOperator) resultOperator; + + _additionalCriteria.Add(q => q.SetMaxResults(1)); + } + + private bool IsPositionalOperator(ResultOperatorBase resultOperator) + { + return resultOperator is FirstResultOperator; + } + + private void ProcessAggregateOperator(ResultOperatorBase resultOperator) + { + HqlTreeNode aggregateNode; + + if (resultOperator is AverageResultOperator) + { + aggregateNode = _hqlTreeBuilder.Average(); + } + else if (resultOperator is SumResultOperator) + { + aggregateNode = _hqlTreeBuilder.Sum(); + } + else if (resultOperator is MinResultOperator) + { + aggregateNode = _hqlTreeBuilder.Min(); + } + else + { + aggregateNode = _hqlTreeBuilder.Max(); + } + + _inputInfo = resultOperator.GetOutputDataInfo(_inputInfo); + + HqlTreeNode child = _selectClause.Children.Single(); + + _selectClause.ClearChildren(); + + aggregateNode.AddChild(child); + + _selectClause.AddChild(_hqlTreeBuilder.Cast(aggregateNode, _inputInfo.DataType)); + } + + private void ProcessCountOperator(ResultOperatorBase resultOperator) + { + HqlTreeNode count = _hqlTreeBuilder.Count(_hqlTreeBuilder.RowStar()); + + if (resultOperator is CountResultOperator) + { + // Need to cast to an int (Hql defaults to long counts) + count = _hqlTreeB... [truncated message content] |