diff --git a/Bson/Serialization/BsonClassMap.cs b/Bson/Serialization/BsonClassMap.cs index c5c04cd24a..e0cc26e4e4 100644 --- a/Bson/Serialization/BsonClassMap.cs +++ b/Bson/Serialization/BsonClassMap.cs @@ -1031,17 +1031,19 @@ namespace MongoDB.Bson.Serialization { private Func GetCreator() { if (creator == null) { - Expression expression; + Expression body; var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; var defaultConstructor = classType.GetConstructor(bindingFlags, null, new Type[0], null); if (defaultConstructor != null) { - expression = Expression.New(defaultConstructor); + // lambdaExpression = () => (object) new TClass() + body = Expression.New(defaultConstructor); } else { - var getUnitializedObjectInfo = typeof(FormatterServices).GetMethod("GetUninitializedObject", BindingFlags.Public | BindingFlags.Static); - expression = Expression.Call(getUnitializedObjectInfo, Expression.Constant(classType)); + // lambdaExpression = () => FormatterServices.GetUninitializedObject(classType) + var getUnitializedObjectMethodInfo = typeof(FormatterServices).GetMethod("GetUninitializedObject", BindingFlags.Public | BindingFlags.Static); + body = Expression.Call(getUnitializedObjectMethodInfo, Expression.Constant(classType)); } - var lambda = Expression.Lambda>(expression); - creator = lambda.Compile(); + var lambdaExpression = Expression.Lambda>(body); + creator = lambdaExpression.Compile(); } return creator; } @@ -1056,14 +1058,15 @@ namespace MongoDB.Bson.Serialization { shouldSerializeMethodInfo.IsPublic && shouldSerializeMethodInfo.ReturnType == typeof(bool) ) { - // we need to construct a lambda wich does the following - // (obj) => obj.ShouldSerializeXyz() - var parameter = Expression.Parameter(typeof(object), "obj"); - var body = Expression.Call( - Expression.Convert(parameter, classType), - shouldSerializeMethodInfo + // lambdaExpression = (obj) => ((TClass) obj).ShouldSerializeXyz() + var objParameter = Expression.Parameter(typeof(object), "obj"); + var lambdaExpression = Expression.Lambda>( + Expression.Call( + Expression.Convert(objParameter, classType), + shouldSerializeMethodInfo + ), + objParameter ); - var lambdaExpression = Expression.Lambda>(body, parameter); return lambdaExpression.Compile(); } else { return null; diff --git a/Bson/Serialization/BsonMemberMap.cs b/Bson/Serialization/BsonMemberMap.cs index 9c2c2d9277..e3ecec101a 100755 --- a/Bson/Serialization/BsonMemberMap.cs +++ b/Bson/Serialization/BsonMemberMap.cs @@ -420,19 +420,20 @@ namespace MongoDB.Bson.Serialization { } } - var instance = Expression.Parameter(typeof(object), "obj"); - var lambda = Expression.Lambda>( + // lambdaExpression = (obj) => (object) ((TClass) obj).Member + var objParameter = Expression.Parameter(typeof(object), "obj"); + var lambdaExpression = Expression.Lambda>( Expression.Convert( Expression.MakeMemberAccess( - Expression.Convert(instance, memberInfo.DeclaringType), + Expression.Convert(objParameter, memberInfo.DeclaringType), memberInfo ), typeof(object) ), - instance + objParameter ); - return lambda.Compile(); + return lambdaExpression.Compile(); } private Action GetPropertySetter() { @@ -443,19 +444,20 @@ namespace MongoDB.Bson.Serialization { throw new BsonSerializationException(message); } - var instance = Expression.Parameter(typeof(object), "obj"); - var argument = Expression.Parameter(typeof(object), "a"); - var lambda = Expression.Lambda>( + // lambdaExpression = (obj, value) => ((TClass) obj).SetMethod((TMember) value) + var objParameter = Expression.Parameter(typeof(object), "obj"); + var valueParameter = Expression.Parameter(typeof(object), "value"); + var lambdaExpression = Expression.Lambda>( Expression.Call( - Expression.Convert(instance, memberInfo.DeclaringType), + Expression.Convert(objParameter, memberInfo.DeclaringType), setMethodInfo, - Expression.Convert(argument, memberType) + Expression.Convert(valueParameter, memberType) ), - instance, - argument + objParameter, + valueParameter ); - return lambda.Compile(); + return lambdaExpression.Compile(); } #endregion } diff --git a/Driver/Driver.csproj b/Driver/Driver.csproj index 5719ebd088..af815ce2e2 100644 --- a/Driver/Driver.csproj +++ b/Driver/Driver.csproj @@ -179,6 +179,13 @@ + + + + + + + diff --git a/Driver/Linq/MongoLinqExtensionMethods.cs b/Driver/Linq/MongoLinqExtensionMethods.cs new file mode 100644 index 0000000000..0a1ca28065 --- /dev/null +++ b/Driver/Linq/MongoLinqExtensionMethods.cs @@ -0,0 +1,42 @@ +/* Copyright 2010-2011 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; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading; + +namespace MongoDB.Driver.Linq { + /// + /// Static class that contains the Mongo Linq extension methods. + /// + public static class MongoLinqExtensionMethods { + /// + /// Returns an instance of IQueryable{{T}} for a MongoCollection. + /// + /// The type of the returned documents. + /// The name of the collection. + /// An instance of IQueryable{{T}} for a MongoCollection. + public static IQueryable AsQueryable( + this MongoCollection collection + ) { + var provider = new MongoQueryProvider(collection); + return new MongoQueryable(provider); + } + } +} diff --git a/Driver/Linq/MongoLinqFindQuery.cs b/Driver/Linq/MongoLinqFindQuery.cs new file mode 100644 index 0000000000..4a97655985 --- /dev/null +++ b/Driver/Linq/MongoLinqFindQuery.cs @@ -0,0 +1,59 @@ +/* Copyright 2010-2011 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; +using System.Threading; + +namespace MongoDB.Driver.Linq { + /// + /// Represents a LINQ query that has been translated to an equivalent MongoDB Find query. + /// + public class MongoLinqFindQuery : MongoLinqQuery { + #region private fields + private IMongoQuery query; + #endregion + + #region constructor + /// + /// Initializes a new instance of the MongoLinqFindQuery class. + /// + /// The collection being queried. + /// The query. + public MongoLinqFindQuery( + MongoCollection collection, + IMongoQuery query + ) + : base(collection) { + this.query = query; + } + #endregion + + #region public methods + /// + /// Executes the translated Find query. + /// + /// The result of executing the translated Find query. + public override IEnumerator GetEnumerator() { + var cursor = collection.FindAs(query); + // TODO: modify the cursor with things like sort order, skip and limit + return cursor.GetEnumerator(); + } + #endregion + } +} diff --git a/Driver/Linq/MongoLinqQuery.cs b/Driver/Linq/MongoLinqQuery.cs new file mode 100644 index 0000000000..dee2255f47 --- /dev/null +++ b/Driver/Linq/MongoLinqQuery.cs @@ -0,0 +1,66 @@ +/* Copyright 2010-2011 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; +using System.Threading; + +namespace MongoDB.Driver.Linq { + /// + /// Represents a LINQ query that has been translated to a MongoDB query. + /// + public abstract class MongoLinqQuery { + #region protected fields + /// + /// The collection being queried. + /// + protected MongoCollection collection; + #endregion + + #region constructors + /// + /// Initializes a new instance of the MongoLinqQuery class. + /// + /// The collection being queried. + protected MongoLinqQuery( + MongoCollection collection + ) { + this.collection = collection; + } + #endregion + + #region public methods + /// + /// Executes a query that returns a single result (overridden by subclasses). + /// + /// The result of executing the query. + public virtual object Execute() { + throw new NotSupportedException(); + } + + /// + /// Gets an enumerator for the results of a query that returns multiple results (overridden by subclasses). + /// + /// + /// + public virtual IEnumerator GetEnumerator() { + throw new NotSupportedException(); + } + #endregion + } +} diff --git a/Driver/Linq/MongoLinqTranslator.cs b/Driver/Linq/MongoLinqTranslator.cs new file mode 100644 index 0000000000..31907ad660 --- /dev/null +++ b/Driver/Linq/MongoLinqTranslator.cs @@ -0,0 +1,45 @@ +/* Copyright 2010-2011 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; +using System.Threading; + +namespace MongoDB.Driver.Linq { + /// + /// A translator from LINQ expression queries to Mongo queries. + /// + public static class MongoLinqTranslator { + #region public static methods + /// + /// A translator from LINQ queries to MongoDB queries. + /// + /// The collection being queried. + /// The LINQ query. + /// An instance of MongoLinqQuery. + public static MongoLinqQuery Translate( + MongoCollection collection, + Expression expression + ) { + // total hack just to test the initial LINQ framework + var query = MongoDB.Driver.Builders.Query.EQ("X", 1); + return new MongoLinqFindQuery(collection, query); + } + #endregion + } +} diff --git a/Driver/Linq/MongoQueryProvider.cs b/Driver/Linq/MongoQueryProvider.cs new file mode 100644 index 0000000000..f5737c6b17 --- /dev/null +++ b/Driver/Linq/MongoQueryProvider.cs @@ -0,0 +1,233 @@ +/* Copyright 2010-2011 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; +using System.Threading; +using System.Reflection; + +namespace MongoDB.Driver.Linq { + /// + /// An implementation of IQueryProvider for querying a MongoDB collection. + /// + public class MongoQueryProvider : IQueryProvider { + #region private static fields + private static Dictionary> createQueryDelegates = new Dictionary>(); + private static MethodInfo createQueryGenericMethodDefinition; + private static Dictionary> executeDelegates = new Dictionary>(); + private static MethodInfo executeGenericMethodDefinition; + private static object staticLock = new object(); + #endregion + + #region private fields + private MongoCollection collection; + #endregion + + #region static constructor + static MongoQueryProvider() { + foreach (var methodInfo in typeof(MongoQueryProvider).GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) { + if (methodInfo.Name == "CreateQuery" && methodInfo.IsGenericMethodDefinition) { + createQueryGenericMethodDefinition = methodInfo; + } + if (methodInfo.Name == "Execute" && methodInfo.IsGenericMethodDefinition) { + executeGenericMethodDefinition = methodInfo; + } + } + } + #endregion + + #region constructors + /// + /// Initializes a new instance of the MongoQueryProvider class. + /// + public MongoQueryProvider( + MongoCollection collection + ) { + if (collection == null) { + throw new ArgumentNullException("collection"); + } + this.collection = collection; + } + #endregion + + #region private static methods + private static Func GetCreateQueryDelegate( + Type type + ) { + lock (staticLock) { + Func createQueryDelegate; + if (!createQueryDelegates.TryGetValue(type, out createQueryDelegate)) { + var createQueryMethodInfo = createQueryGenericMethodDefinition.MakeGenericMethod(type); + + // lambdaExpression = (provider, expression) => (IQueryable) provider.CreateQuery(expression) + var providerParameter = Expression.Parameter(typeof(MongoQueryProvider), "provider"); + var expressionParameter = Expression.Parameter(typeof(Expression), "expression"); + var lambdaExpression = Expression.Lambda>( + Expression.Convert( + Expression.Call(providerParameter, createQueryMethodInfo, expressionParameter), + typeof(IQueryable) + ), + providerParameter, + expressionParameter + ); + createQueryDelegate = lambdaExpression.Compile(); + createQueryDelegates.Add(type, createQueryDelegate); + } + return createQueryDelegate; + } + } + + private static Func GetExecuteDelegate( + Type type + ) { + lock (staticLock) { + Func executeDelegate; + if (!executeDelegates.TryGetValue(type, out executeDelegate)) { + var executeMethodInfo = executeGenericMethodDefinition.MakeGenericMethod(type); + + // lambdaExpression = (provider, expression) => (object) provider.Execute(expression) + var providerParameter = Expression.Parameter(typeof(MongoQueryProvider), "provider"); + var expressionParameter = Expression.Parameter(typeof(Expression), "expression"); + var lambdaExpression = Expression.Lambda>( + Expression.Convert( + Expression.Call(providerParameter, executeMethodInfo, expressionParameter), + typeof(object) + ), + providerParameter, + expressionParameter + ); + executeDelegate = lambdaExpression.Compile(); + executeDelegates.Add(type, executeDelegate); + } + return executeDelegate; + } + } + #endregion + + #region public methods + /// + /// Creates a new instance of MongoQueryable{{T}} for this provider. + /// + /// The type of the returned elements. + /// The query expression. + /// A new instance of MongoQueryable{{T}}. + public IQueryable CreateQuery( + Expression expression + ) { + if (expression == null) { + throw new ArgumentNullException("expression"); + } + if (!typeof(IQueryable).IsAssignableFrom(expression.Type)) { + throw new ArgumentOutOfRangeException("expression"); + } + return new MongoQueryable(this, expression); + } + + /// + /// Creates a new instance MongoQueryable{{T}} for this provider. Calls the generic CreateQuery{{T}} + /// to actually create the new MongoQueryable{{T}} instance. + /// + /// The query expression. + /// A new instance of MongoQueryable{{T}}. + public IQueryable CreateQuery( + Expression expression + ) { + if (expression == null) { + throw new ArgumentNullException("expression"); + } + try { + var elementType = TypeSystem.GetElementType(expression.Type); + var createQueryDelegate = GetCreateQueryDelegate(elementType); + return createQueryDelegate(this, expression); + } catch (TargetInvocationException ex) { + throw ex.InnerException; + } + } + + /// + /// Executes a query. + /// + /// The type of the result. + /// The query expression. + /// The result of the query. + public TResult Execute( + Expression expression + ) { + if (expression == null) { + throw new ArgumentNullException("expression"); + } + if (!typeof(TResult).IsAssignableFrom(expression.Type)) { + throw new ArgumentException("Argument expression is not valid."); + } + var translatedQuery = MongoLinqTranslator.Translate(collection, expression); + return (TResult) translatedQuery.Execute(); + } + + /// + /// Executes a query. Calls the generic method Execute{{T}} to actually execute the query. + /// + /// The query expression. + /// The result of the query. + public object Execute( + Expression expression + ) { + if (expression == null) { + throw new ArgumentNullException("expression"); + } + try { + var resultType = expression.Type; + var executeDelegate = GetExecuteDelegate(resultType); + return executeDelegate(this, expression); + } catch (TargetInvocationException ex) { + throw ex.InnerException; + } + } + + /// + /// Gets an enumerator by executing the query. + /// + /// Type element type. + /// The LINQ expression. + /// An enumerator for the results of the query. + public IEnumerator GetEnumerator( + Expression expression + ) { + if (expression == null) { + throw new ArgumentNullException("expression"); + } + if (!typeof(IEnumerable).IsAssignableFrom(expression.Type)) { + throw new ArgumentException("Argument expression is not valid."); + } + var translatedQuery = MongoLinqTranslator.Translate(collection, expression); + return translatedQuery.GetEnumerator(); + } + + /// + /// Gets a string representation of the LINQ expression translated to a MongoDB query. + /// + /// The LINQ expression. + /// A string. + public string GetQueryText( + Expression expression + ) { + var translatedQuery = MongoLinqTranslator.Translate(collection, expression); + return translatedQuery.ToString(); + } + #endregion + } +} diff --git a/Driver/Linq/MongoQueryable.cs b/Driver/Linq/MongoQueryable.cs new file mode 100644 index 0000000000..a3b4547947 --- /dev/null +++ b/Driver/Linq/MongoQueryable.cs @@ -0,0 +1,107 @@ +/* Copyright 2010-2011 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; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading; + +namespace MongoDB.Driver.Linq { + /// + /// An implementation of IQueryable{{T}} for querying a MongoDB collection. + /// + public class MongoQueryable : IOrderedQueryable { + #region private fields + private MongoQueryProvider provider; + private Expression expression; + #endregion + + #region constructors + /// + /// Initializes a new instance of the MongoQueryable class. + /// + public MongoQueryable( + MongoQueryProvider provider + ) { + if (provider == null) { + throw new ArgumentNullException("provider"); + } + this.provider = provider; + this.expression = Expression.Constant(this); + } + + /// + /// Initializes a new instance of the MongoQueryable class. + /// + public MongoQueryable( + MongoQueryProvider provider, + Expression expression + ) { + if (provider == null) { + throw new ArgumentNullException("provider"); + } + if (expression == null) { + throw new ArgumentNullException("expression"); + } + if (!typeof(IQueryable).IsAssignableFrom(expression.Type)) { + throw new ArgumentOutOfRangeException("expression"); + } + this.provider = provider; + this.expression = expression; + } + #endregion + + #region public methods + /// + /// Gets an enumerator for the results of a MongoDB LINQ query. + /// + /// + public IEnumerator GetEnumerator() { + return provider.GetEnumerator(expression); + } + + /// + /// Gets a string representation of the MongoDB query obtained by translating the LINQ query. + /// + /// + public override string ToString() { + return provider.GetQueryText(expression); + } + #endregion + + #region explicit implementation of IEnumerable + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + #endregion + + #region explicit implementation of IQueryable + Type IQueryable.ElementType { + get { return typeof(T); } + } + + Expression IQueryable.Expression { + get { return expression; } + } + + IQueryProvider IQueryable.Provider { + get { return provider; } + } + #endregion + } +} diff --git a/Driver/Linq/TypeSystem.cs b/Driver/Linq/TypeSystem.cs new file mode 100644 index 0000000000..0beb19f877 --- /dev/null +++ b/Driver/Linq/TypeSystem.cs @@ -0,0 +1,64 @@ +/* Copyright 2010-2011 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 System.Threading; + +namespace MongoDB.Driver.Linq { + // taken from http://msdn.microsoft.com/en-us/library/bb546158.aspx + internal static class TypeSystem { + internal static Type GetElementType(Type seqType) { + Type ienum = FindIEnumerable(seqType); + if (ienum == null) { return seqType; } + return ienum.GetGenericArguments()[0]; + } + + private static Type FindIEnumerable(Type seqType) { + if (seqType == null || seqType == typeof(string)) { + return null; + } + + if (seqType.IsArray) { + return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType()); + } + + if (seqType.IsGenericType) { + foreach (Type arg in seqType.GetGenericArguments()) { + Type ienum = typeof(IEnumerable<>).MakeGenericType(arg); + if (ienum.IsAssignableFrom(seqType)) { + return ienum; + } + } + } + + Type[] ifaces = seqType.GetInterfaces(); + if (ifaces != null && ifaces.Length > 0) { + foreach (Type iface in ifaces) { + Type ienum = FindIEnumerable(iface); + if (ienum != null) { return ienum; } + } + } + + if (seqType.BaseType != null && seqType.BaseType != typeof(object)) { + return FindIEnumerable(seqType.BaseType); + } + + return null; + } + } +} diff --git a/DriverOnlineTests/DriverOnlineTests.csproj b/DriverOnlineTests/DriverOnlineTests.csproj index 08a8d064d8..23b6853650 100644 --- a/DriverOnlineTests/DriverOnlineTests.csproj +++ b/DriverOnlineTests/DriverOnlineTests.csproj @@ -119,6 +119,9 @@ + + + diff --git a/DriverOnlineTests/Linq/MongoLinqFindQueryTests.cs b/DriverOnlineTests/Linq/MongoLinqFindQueryTests.cs new file mode 100644 index 0000000000..90db566659 --- /dev/null +++ b/DriverOnlineTests/Linq/MongoLinqFindQueryTests.cs @@ -0,0 +1,69 @@ +/* Copyright 2010-2011 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.DriverOnlineTests.Linq { + [TestFixture] + public class MongoLinqFindQueryTests { + private class C { + public ObjectId Id { get; set; } + public int X { get; set; } + public int Y { get; set; } + } + + private MongoServer server; + private MongoDatabase database; + private MongoCollection collection; + + [TestFixtureSetUp] + public void Setup() { + server = MongoServer.Create("mongodb://localhost/?safe=true"); + server.Connect(); + database = server["onlinetests"]; + collection = database.GetCollection("linqtests"); + + collection.Drop(); + collection.Insert(new C { X = 1, Y = 11 }); + collection.Insert(new C { X = 2, Y = 12 }); + collection.Insert(new C { X = 3, Y = 13 }); + collection.Insert(new C { X = 4, Y = 14 }); + collection.Insert(new C { X = 5, Y = 15 }); + } + + [Test] + public void TestQueryXEquals1() { + var query = from c in collection.AsQueryable() + where c.X == 1 + select c; + var count = 0; + foreach (var c in query) { + Assert.AreEqual(1, c.X); + count++; + } + Assert.AreEqual(1, count); + } + } +} diff --git a/DriverOnlineTests/Linq/MongoQueryProviderTests.cs b/DriverOnlineTests/Linq/MongoQueryProviderTests.cs new file mode 100644 index 0000000000..e50a9ef69d --- /dev/null +++ b/DriverOnlineTests/Linq/MongoQueryProviderTests.cs @@ -0,0 +1,75 @@ +/* Copyright 2010-2011 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; +using NUnit.Framework; + +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Driver; +using MongoDB.Driver.Builders; +using MongoDB.Driver.Linq; + +namespace MongoDB.DriverOnlineTests.Linq { + [TestFixture] + public class MongoQueryProviderTests { + private class C { + public ObjectId Id { get; set; } + public int X { get; set; } + public int Y { get; set; } + } + + private MongoServer server; + private MongoDatabase database; + private MongoCollection collection; + + [TestFixtureSetUp] + public void Setup() { + server = MongoServer.Create("mongodb://localhost/?safe=true"); + server.Connect(); + database = server["onlinetests"]; + collection = database["linqtests"]; + } + + [Test] + public void TestConstructor() { + var provider = new MongoQueryProvider(collection); + } + + [Test] + public void TestCreateQuery() { + var expression = collection.AsQueryable().Expression; + var provider = new MongoQueryProvider(collection); + var query = provider.CreateQuery(expression); + Assert.AreSame(typeof(C), query.ElementType); + Assert.AreSame(provider, query.Provider); + Assert.AreSame(expression, query.Expression); + } + + [Test] + public void TestCreateQueryNonGeneric() { + var expression = collection.AsQueryable().Expression; + var provider = new MongoQueryProvider(collection); + var query = provider.CreateQuery(expression); + Assert.AreSame(typeof(C), query.ElementType); + Assert.AreSame(provider, query.Provider); + Assert.AreSame(expression, query.Expression); + } + } +} diff --git a/DriverOnlineTests/Linq/MongoQueryableTests.cs b/DriverOnlineTests/Linq/MongoQueryableTests.cs new file mode 100644 index 0000000000..f4acf5a161 --- /dev/null +++ b/DriverOnlineTests/Linq/MongoQueryableTests.cs @@ -0,0 +1,67 @@ +/* Copyright 2010-2011 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; +using NUnit.Framework; + +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Driver; +using MongoDB.Driver.Builders; +using MongoDB.Driver.Linq; + +namespace MongoDB.DriverOnlineTests.Linq { + [TestFixture] + public class MongoQueryableTests { + private class C { + public ObjectId Id { get; set; } + public int X { get; set; } + public int Y { get; set; } + } + + private MongoServer server; + private MongoDatabase database; + private MongoCollection collection; + + [TestFixtureSetUp] + public void Setup() { + server = MongoServer.Create("mongodb://localhost/?safe=true"); + server.Connect(); + database = server["onlinetests"]; + collection = database["linqtests"]; + } + + [Test] + public void TestConstructorWithOneArgument() { + var provider = new MongoQueryProvider(collection); + var iqueryable = (IQueryable) new MongoQueryable(provider); + Assert.AreSame(typeof(C), iqueryable.ElementType); + Assert.AreSame(provider, iqueryable.Provider); + } + + [Test] + public void TestConstructorWithTwoArguments() { + var queryable = collection.AsQueryable(); + var iqueryable = (IQueryable) new MongoQueryable((MongoQueryProvider) queryable.Provider, queryable.Expression); + Assert.AreSame(typeof(C), iqueryable.ElementType); + Assert.AreSame(queryable.Provider, iqueryable.Provider); + Assert.AreSame(queryable.Expression, iqueryable.Expression); + } + } +}