From 3b46a193c069a207eb8dfa709c2741cba08d05ee Mon Sep 17 00:00:00 2001 From: rstam Date: Thu, 12 Apr 2012 17:30:42 -0400 Subject: [PATCH] Partial implementation of CSHARP-433. Implemented OfType query operator. Still need to implement "is" operator and comparison of types using "==". --- Driver/Driver.csproj | 1 + .../Expressions/ExpressionParameterFinder.cs | 82 ++++++++ Driver/Linq/Translators/SelectQuery.cs | 122 +++++++++++- DriverUnitTests/DriverUnitTests.csproj | 2 + .../GridFS/MongoGridFSStreamTests.cs | 2 + .../Linq/SelectOfTypeHierarchicalTests.cs | 187 ++++++++++++++++++ DriverUnitTests/Linq/SelectOfTypeTests.cs | 186 +++++++++++++++++ DriverUnitTests/Linq/SelectQueryTests.cs | 9 - 8 files changed, 579 insertions(+), 12 deletions(-) create mode 100644 Driver/Linq/Expressions/ExpressionParameterFinder.cs create mode 100644 DriverUnitTests/Linq/SelectOfTypeHierarchicalTests.cs create mode 100644 DriverUnitTests/Linq/SelectOfTypeTests.cs diff --git a/Driver/Driver.csproj b/Driver/Driver.csproj index 94efa37ee51..ddc4525d65b 100644 --- a/Driver/Driver.csproj +++ b/Driver/Driver.csproj @@ -183,6 +183,7 @@ + diff --git a/Driver/Linq/Expressions/ExpressionParameterFinder.cs b/Driver/Linq/Expressions/ExpressionParameterFinder.cs new file mode 100644 index 00000000000..98729f3ab34 --- /dev/null +++ b/Driver/Linq/Expressions/ExpressionParameterFinder.cs @@ -0,0 +1,82 @@ +/* Copyright 2010-2012 10gen Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; + +namespace MongoDB.Driver.Linq +{ + /// + /// A class that finds the first parameter in an expression. + /// + public class ExpressionParameterFinder : ExpressionVisitor + { + // private fields + private ParameterExpression _parameter; + + // constructors + /// + /// Initializes a new instance of the ExpressionParameterFinder class. + /// + public ExpressionParameterFinder() + { + } + + // public static methods + /// + /// Finds the first parameter in an expression. + /// + /// The expression containing the parameter that should be found. + /// The first parameter found in the expression (or null if none was found). + public static ParameterExpression FindParameter(Expression node) + { + var finder = new ExpressionParameterFinder(); + finder.Visit(node); + return finder._parameter; + } + + // protected methods + /// + /// Visits an Expression. + /// + /// The Expression. + /// The Expression (posibly modified). + protected override Expression Visit(Expression node) + { + if (_parameter != null) + { + return node; // exit faster if we've already found the parameter + } + return base.Visit(node); + } + + /// + /// Remembers this parameter if it is the first parameter found. + /// + /// The ParameterExpression. + /// The ParameterExpression. + protected override Expression VisitParameter(ParameterExpression node) + { + if (_parameter == null) + { + _parameter = node; + } + return node; + } + } +} diff --git a/Driver/Linq/Translators/SelectQuery.cs b/Driver/Linq/Translators/SelectQuery.cs index 88a1402f287..a2aeefae78b 100644 --- a/Driver/Linq/Translators/SelectQuery.cs +++ b/Driver/Linq/Translators/SelectQuery.cs @@ -37,6 +37,7 @@ public class SelectQuery : TranslatedQuery { // private fields private LambdaExpression _where; + private Type _ofType; private List _orderBy; private LambdaExpression _projection; private Expression _skip; @@ -56,6 +57,14 @@ public SelectQuery(MongoCollection collection, Type documentType) } // public properties + /// + /// Gets the final result type if an OfType query operator was used (otherwise null). + /// + public Type OfType + { + get { return _ofType; } + } + /// /// Gets a list of Expressions that defines the sort order (or null if not specified). /// @@ -157,6 +166,21 @@ public override object Execute() cursor.SetLimit(ToInt32(_take)); } + if (_ofType != null) + { + if (_projection == null) + { + var paramExpression = Expression.Parameter(DocumentType, "x"); + var convertExpression = Expression.Convert(paramExpression, _ofType); + _projection = Expression.Lambda(convertExpression, paramExpression); + } + else + { + // TODO: handle projection after OfType + throw new NotSupportedException(); + } + } + IEnumerable enumerable; if (_projection == null) { @@ -208,6 +232,7 @@ public void Translate(Expression expression) } var message = string.Format("Don't know how to translate expression: {0}.", ExpressionFormatter.ToString(expression)); + throw new NotSupportedException(message); } // private methods @@ -1239,10 +1264,39 @@ private void CombinePredicateWithWhereClause(MethodCallExpression methodCallExpr return; } + if (_where.Parameters.Count != 1) + { + throw new MongoInternalException("Where lambda expression should have one parameter."); + } var whereBody = _where.Body; - var predicateBody = ExpressionParameterReplacer.ReplaceParameter(predicate.Body, predicate.Parameters[0], _where.Parameters[0]); + var whereParameter = _where.Parameters[0]; + + if (predicate.Parameters.Count != 1) + { + throw new MongoInternalException("Predicate lambda expression should have one parameter."); + } + var predicateBody = predicate.Body; + var predicateParameter = predicate.Parameters[0]; + + // when using OfType the parameter types might not match (but they do have to be compatible) + ParameterExpression parameter; + if (predicateParameter.Type.IsAssignableFrom(whereParameter.Type)) + { + predicateBody = ExpressionParameterReplacer.ReplaceParameter(predicateBody, predicateParameter, whereParameter); + parameter = whereParameter; + } + else if (whereParameter.Type.IsAssignableFrom(predicateParameter.Type)) + { + whereBody = ExpressionParameterReplacer.ReplaceParameter(whereBody, whereParameter, predicateParameter); + parameter = predicateParameter; + } + else + { + throw new NotSupportedException("Can't combine existing where clause with new predicate because parameter types are incompatible."); + } + var combinedBody = Expression.AndAlso(whereBody, predicateBody); - _where = Expression.Lambda(combinedBody, _where.Parameters.ToArray()); + _where = Expression.Lambda(combinedBody, parameter); } } @@ -1278,7 +1332,9 @@ private object ExecuteDistinct(IMongoQuery query) private BsonSerializationInfo GetSerializationInfo(Expression expression) { - var documentSerializer = BsonSerializer.LookupSerializer(DocumentType); + // when using OfType the documentType used by the parameter might be a subclass of the DocumentType from the collection + var parameterExpression = ExpressionParameterFinder.FindParameter(expression); + var documentSerializer = BsonSerializer.LookupSerializer(parameterExpression.Type); return GetSerializationInfo(documentSerializer, expression); } @@ -1755,6 +1811,9 @@ private void TranslateMethodCall(MethodCallExpression methodCallExpression) case "Min": TranslateMaxMin(methodCallExpression); break; + case "OfType": + TranslateOfType(methodCallExpression); + break; case "OrderBy": case "OrderByDescending": TranslateOrderBy(methodCallExpression); @@ -1781,6 +1840,63 @@ private void TranslateMethodCall(MethodCallExpression methodCallExpression) } } + private void TranslateOfType(MethodCallExpression methodCallExpression) + { + var method = methodCallExpression.Method; + if (method.DeclaringType != typeof(Queryable)) + { + var message = string.Format("OfType method of class {0} is not supported.", BsonUtils.GetFriendlyTypeName(method.DeclaringType)); + throw new NotSupportedException(message); + } + if (!method.IsStatic) + { + throw new NotSupportedException("Expected OfType to be a static method."); + } + if (!method.IsGenericMethod) + { + throw new NotSupportedException("Expected OfType to be a generic method."); + } + var actualType = method.GetGenericArguments()[0]; + + var args = methodCallExpression.Arguments.ToArray(); + if (args.Length != 1) + { + throw new NotSupportedException("Expected OfType method to have a single argument."); + } + var sourceExpression = args[0]; + if (!sourceExpression.Type.IsGenericType) + { + throw new NotSupportedException("Expected source argument to OfType to be a generic type."); + } + var nominalType = sourceExpression.Type.GetGenericArguments()[0]; + + if (nominalType == actualType) + { + return; // nothing to do + } + + if (_projection != null) + { + throw new NotSupportedException("OfType after a projection is not supported."); + } + + var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(nominalType); + var discriminator = discriminatorConvention.GetDiscriminator(nominalType, actualType); + if (discriminator.IsBsonArray) + { + discriminator = discriminator.AsBsonArray[discriminator.AsBsonArray.Count - 1]; + } + + var injectMethodInfo = typeof(LinqToMongo).GetMethod("Inject"); + var query = Query.EQ("_t", discriminator); + var body = Expression.Call(injectMethodInfo, Expression.Constant(query)); + var parameter = Expression.Parameter(nominalType, "x"); + var predicate = Expression.Lambda(body, parameter); + CombinePredicateWithWhereClause(methodCallExpression, predicate); + + _ofType = actualType; + } + private void TranslateOrderBy(MethodCallExpression methodCallExpression) { if (methodCallExpression.Arguments.Count != 2) diff --git a/DriverUnitTests/DriverUnitTests.csproj b/DriverUnitTests/DriverUnitTests.csproj index 2dfd2365a17..09043da7787 100644 --- a/DriverUnitTests/DriverUnitTests.csproj +++ b/DriverUnitTests/DriverUnitTests.csproj @@ -162,6 +162,8 @@ + + diff --git a/DriverUnitTests/GridFS/MongoGridFSStreamTests.cs b/DriverUnitTests/GridFS/MongoGridFSStreamTests.cs index 75aef1980f6..0c99e1be10b 100644 --- a/DriverUnitTests/GridFS/MongoGridFSStreamTests.cs +++ b/DriverUnitTests/GridFS/MongoGridFSStreamTests.cs @@ -282,7 +282,9 @@ public void TestUpdateMD5() { var bytes = new byte[] { 1, 2, 3, 4 }; stream.Write(bytes, 0, 4); +#pragma warning disable 618 // about obsolete BsonBinarySubType.OldBinary stream.UpdateMD5 = false; +#pragma warning restore } fileInfo = _gridFS.FindOne("test"); diff --git a/DriverUnitTests/Linq/SelectOfTypeHierarchicalTests.cs b/DriverUnitTests/Linq/SelectOfTypeHierarchicalTests.cs new file mode 100644 index 00000000000..64e699704fd --- /dev/null +++ b/DriverUnitTests/Linq/SelectOfTypeHierarchicalTests.cs @@ -0,0 +1,187 @@ +/* Copyright 2010-2012 10gen Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; + +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Driver; +using MongoDB.Driver.Builders; +using MongoDB.Driver.Linq; + +namespace MongoDB.DriverUnitTests.Linq +{ + [TestFixture] + public class SelectOfTypeHierarchicalTests + { + [BsonDiscriminator(RootClass = true)] + private class B + { + public ObjectId Id; + public int b; + } + + private class C : B + { + public int c; + } + + private class D : C + { + public int d; + } + + private MongoServer _server; + private MongoDatabase _database; + private MongoCollection _collection; + + [TestFixtureSetUp] + public void Setup() + { + _server = Configuration.TestServer; + _database = Configuration.TestDatabase; + _collection = Configuration.GetTestCollection(); + + _collection.Drop(); + _collection.Insert(new B { Id = ObjectId.GenerateNewId(), b = 1 }); + _collection.Insert(new C { Id = ObjectId.GenerateNewId(), b = 2, c = 2 }); + _collection.Insert(new D { Id = ObjectId.GenerateNewId(), b = 3, c = 3, d = 3 }); + } + + [Test] + public void TestOfTypeB() + { + var query = _collection.AsQueryable().OfType(); + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(B), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.IsNull(selectQuery.Where); + Assert.AreEqual(null, selectQuery.OfType); // OfType ignored because was the same as + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.IsNull(selectQuery.BuildQuery()); + Assert.AreEqual(3, Consume(query)); + } + + [Test] + public void TestOfTypeC() + { + var query = _collection.AsQueryable().OfType(); + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(B), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(B x) => LinqToMongo.Inject({ \"_t\" : \"C\" })", ExpressionFormatter.ToString(selectQuery.Where)); + Assert.AreEqual(typeof(C), selectQuery.OfType); + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"_t\" : \"C\" }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(2, Consume(query)); + } + + [Test] + public void TestOfTypeCWhereCGreaterThan0() + { + var query = _collection.AsQueryable().OfType().Where(c => c.c > 0); + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(B), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(C c) => (LinqToMongo.Inject({ \"_t\" : \"C\" }) && (c.c > 0))", ExpressionFormatter.ToString(selectQuery.Where)); + Assert.AreEqual(typeof(C), selectQuery.OfType); + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"_t\" : \"C\", \"c\" : { \"$gt\" : 0 } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(2, Consume(query)); + } + + [Test] + public void TestOfTypeD() + { + var query = _collection.AsQueryable().OfType(); + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(B), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(B x) => LinqToMongo.Inject({ \"_t\" : \"D\" })", ExpressionFormatter.ToString(selectQuery.Where)); + Assert.AreEqual(typeof(D), selectQuery.OfType); + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"_t\" : \"D\" }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(1, Consume(query)); + } + + [Test] + public void TestWhereBGreaterThan0OfTypeCWhereCGreaterThan0() + { + var query = _collection.AsQueryable().Where(b => b.b > 0).OfType().Where(c => c.c > 0); + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(B), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(C c) => (((c.b > 0) && LinqToMongo.Inject({ \"_t\" : \"C\" })) && (c.c > 0))", ExpressionFormatter.ToString(selectQuery.Where)); + Assert.AreEqual(typeof(C), selectQuery.OfType); + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"b\" : { \"$gt\" : 0 }, \"_t\" : \"C\", \"c\" : { \"$gt\" : 0 } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(2, Consume(query)); + } + + private int Consume(IQueryable query) + { + var count = 0; + foreach (var c in query) + { + count++; + } + return count; + } + } +} diff --git a/DriverUnitTests/Linq/SelectOfTypeTests.cs b/DriverUnitTests/Linq/SelectOfTypeTests.cs new file mode 100644 index 00000000000..cc11c67c688 --- /dev/null +++ b/DriverUnitTests/Linq/SelectOfTypeTests.cs @@ -0,0 +1,186 @@ +/* Copyright 2010-2012 10gen Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; + +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Driver; +using MongoDB.Driver.Builders; +using MongoDB.Driver.Linq; + +namespace MongoDB.DriverUnitTests.Linq +{ + [TestFixture] + public class SelectOfTypeTests + { + private class B + { + public ObjectId Id; + public int b; + } + + private class C : B + { + public int c; + } + + private class D : C + { + public int d; + } + + private MongoServer _server; + private MongoDatabase _database; + private MongoCollection _collection; + + [TestFixtureSetUp] + public void Setup() + { + _server = Configuration.TestServer; + _database = Configuration.TestDatabase; + _collection = Configuration.GetTestCollection(); + + _collection.Drop(); + _collection.Insert(new B { Id = ObjectId.GenerateNewId(), b = 1 }); + _collection.Insert(new C { Id = ObjectId.GenerateNewId(), b = 2, c = 2 }); + _collection.Insert(new D { Id = ObjectId.GenerateNewId(), b = 3, c = 3, d = 3 }); + } + + [Test] + public void TestOfTypeB() + { + var query = _collection.AsQueryable().OfType(); + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(B), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.IsNull(selectQuery.Where); + Assert.AreEqual(null, selectQuery.OfType); // OfType ignored because was the same as + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.IsNull(selectQuery.BuildQuery()); + Assert.AreEqual(3, Consume(query)); + } + + [Test] + public void TestOfTypeC() + { + var query = _collection.AsQueryable().OfType(); + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(B), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(B x) => LinqToMongo.Inject({ \"_t\" : \"C\" })", ExpressionFormatter.ToString(selectQuery.Where)); + Assert.AreEqual(typeof(C), selectQuery.OfType); + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"_t\" : \"C\" }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(1, Consume(query)); // should match 2 but for that you need to use the hierarchical discriminator + } + + [Test] + public void TestOfTypeCWhereCGreaterThan0() + { + var query = _collection.AsQueryable().OfType().Where(c => c.c > 0); + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(B), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(C c) => (LinqToMongo.Inject({ \"_t\" : \"C\" }) && (c.c > 0))", ExpressionFormatter.ToString(selectQuery.Where)); + Assert.AreEqual(typeof(C), selectQuery.OfType); + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"_t\" : \"C\", \"c\" : { \"$gt\" : 0 } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(1, Consume(query)); // should match 2 but for that you need to use the hierarchical discriminator + } + + [Test] + public void TestOfTypeD() + { + var query = _collection.AsQueryable().OfType(); + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(B), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(B x) => LinqToMongo.Inject({ \"_t\" : \"D\" })", ExpressionFormatter.ToString(selectQuery.Where)); + Assert.AreEqual(typeof(D), selectQuery.OfType); + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"_t\" : \"D\" }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(1, Consume(query)); + } + + [Test] + public void TestWhereBGreaterThan0OfTypeCWhereCGreaterThan0() + { + var query = _collection.AsQueryable().Where(b => b.b > 0).OfType().Where(c => c.c > 0); + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(B), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(C c) => (((c.b > 0) && LinqToMongo.Inject({ \"_t\" : \"C\" })) && (c.c > 0))", ExpressionFormatter.ToString(selectQuery.Where)); + Assert.AreEqual(typeof(C), selectQuery.OfType); + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"b\" : { \"$gt\" : 0 }, \"_t\" : \"C\", \"c\" : { \"$gt\" : 0 } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(1, Consume(query)); // should match 2 but for that you need to use the hierarchical discriminator + } + + private int Consume(IQueryable query) + { + var count = 0; + foreach (var c in query) + { + count++; + } + return count; + } + } +} diff --git a/DriverUnitTests/Linq/SelectQueryTests.cs b/DriverUnitTests/Linq/SelectQueryTests.cs index 2f91261de90..5b7d813f753 100644 --- a/DriverUnitTests/Linq/SelectQueryTests.cs +++ b/DriverUnitTests/Linq/SelectQueryTests.cs @@ -1314,15 +1314,6 @@ public void TestMinXYWithSelector() Assert.AreEqual(11, result.Y); } - [Test] - [ExpectedException(typeof(NotSupportedException), ExpectedMessage = "The OfType query operator is not supported.")] - public void TestOfType() - { - var query = (from c in _collection.AsQueryable() - select c).OfType(); - query.ToList(); // execute query - } - [Test] public void TestOrderByAscending() {