Browse Source
Initial framework of LINQ implementation. Please note that this doesn't really do anything yet because the MongoLinqTranslator class is stubbed out.
pull/70/merge
Initial framework of LINQ implementation. Please note that this doesn't really do anything yet because the MongoLinqTranslator class is stubbed out.
pull/70/merge

14 changed files with 868 additions and 26 deletions
-
27Bson/Serialization/BsonClassMap.cs
-
28Bson/Serialization/BsonMemberMap.cs
-
7Driver/Driver.csproj
-
42Driver/Linq/MongoLinqExtensionMethods.cs
-
59Driver/Linq/MongoLinqFindQuery.cs
-
66Driver/Linq/MongoLinqQuery.cs
-
45Driver/Linq/MongoLinqTranslator.cs
-
233Driver/Linq/MongoQueryProvider.cs
-
107Driver/Linq/MongoQueryable.cs
-
64Driver/Linq/TypeSystem.cs
-
3DriverOnlineTests/DriverOnlineTests.csproj
-
69DriverOnlineTests/Linq/MongoLinqFindQueryTests.cs
-
75DriverOnlineTests/Linq/MongoQueryProviderTests.cs
-
67DriverOnlineTests/Linq/MongoQueryableTests.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 { |
|||
/// <summary>
|
|||
/// Static class that contains the Mongo Linq extension methods.
|
|||
/// </summary>
|
|||
public static class MongoLinqExtensionMethods { |
|||
/// <summary>
|
|||
/// Returns an instance of IQueryable{{T}} for a MongoCollection.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of the returned documents.</typeparam>
|
|||
/// <param name="collection">The name of the collection.</param>
|
|||
/// <returns>An instance of IQueryable{{T}} for a MongoCollection.</returns>
|
|||
public static IQueryable<T> AsQueryable<T>( |
|||
this MongoCollection collection |
|||
) { |
|||
var provider = new MongoQueryProvider(collection); |
|||
return new MongoQueryable<T>(provider); |
|||
} |
|||
} |
|||
} |
@ -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 { |
|||
/// <summary>
|
|||
/// Represents a LINQ query that has been translated to an equivalent MongoDB Find query.
|
|||
/// </summary>
|
|||
public class MongoLinqFindQuery : MongoLinqQuery { |
|||
#region private fields
|
|||
private IMongoQuery query; |
|||
#endregion
|
|||
|
|||
#region constructor
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the MongoLinqFindQuery class.
|
|||
/// </summary>
|
|||
/// <param name="collection">The collection being queried.</param>
|
|||
/// <param name="query">The query.</param>
|
|||
public MongoLinqFindQuery( |
|||
MongoCollection collection, |
|||
IMongoQuery query |
|||
) |
|||
: base(collection) { |
|||
this.query = query; |
|||
} |
|||
#endregion
|
|||
|
|||
#region public methods
|
|||
/// <summary>
|
|||
/// Executes the translated Find query.
|
|||
/// </summary>
|
|||
/// <returns>The result of executing the translated Find query.</returns>
|
|||
public override IEnumerator<T> GetEnumerator<T>() { |
|||
var cursor = collection.FindAs<T>(query); |
|||
// TODO: modify the cursor with things like sort order, skip and limit
|
|||
return cursor.GetEnumerator(); |
|||
} |
|||
#endregion
|
|||
} |
|||
} |
@ -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 { |
|||
/// <summary>
|
|||
/// Represents a LINQ query that has been translated to a MongoDB query.
|
|||
/// </summary>
|
|||
public abstract class MongoLinqQuery { |
|||
#region protected fields
|
|||
/// <summary>
|
|||
/// The collection being queried.
|
|||
/// </summary>
|
|||
protected MongoCollection collection; |
|||
#endregion
|
|||
|
|||
#region constructors
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the MongoLinqQuery class.
|
|||
/// </summary>
|
|||
/// <param name="collection">The collection being queried.</param>
|
|||
protected MongoLinqQuery( |
|||
MongoCollection collection |
|||
) { |
|||
this.collection = collection; |
|||
} |
|||
#endregion
|
|||
|
|||
#region public methods
|
|||
/// <summary>
|
|||
/// Executes a query that returns a single result (overridden by subclasses).
|
|||
/// </summary>
|
|||
/// <returns>The result of executing the query.</returns>
|
|||
public virtual object Execute() { |
|||
throw new NotSupportedException(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets an enumerator for the results of a query that returns multiple results (overridden by subclasses).
|
|||
/// </summary>
|
|||
/// <typeparam name="T"></typeparam>
|
|||
/// <returns></returns>
|
|||
public virtual IEnumerator<T> GetEnumerator<T>() { |
|||
throw new NotSupportedException(); |
|||
} |
|||
#endregion
|
|||
} |
|||
} |
@ -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 { |
|||
/// <summary>
|
|||
/// A translator from LINQ expression queries to Mongo queries.
|
|||
/// </summary>
|
|||
public static class MongoLinqTranslator { |
|||
#region public static methods
|
|||
/// <summary>
|
|||
/// A translator from LINQ queries to MongoDB queries.
|
|||
/// </summary>
|
|||
/// <param name="collection">The collection being queried.</param>
|
|||
/// <param name="expression">The LINQ query.</param>
|
|||
/// <returns>An instance of MongoLinqQuery.</returns>
|
|||
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
|
|||
} |
|||
} |
@ -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 { |
|||
/// <summary>
|
|||
/// An implementation of IQueryProvider for querying a MongoDB collection.
|
|||
/// </summary>
|
|||
public class MongoQueryProvider : IQueryProvider { |
|||
#region private static fields
|
|||
private static Dictionary<Type, Func<MongoQueryProvider, Expression, IQueryable>> createQueryDelegates = new Dictionary<Type, Func<MongoQueryProvider, Expression, IQueryable>>(); |
|||
private static MethodInfo createQueryGenericMethodDefinition; |
|||
private static Dictionary<Type, Func<MongoQueryProvider, Expression, object>> executeDelegates = new Dictionary<Type, Func<MongoQueryProvider, Expression, object>>(); |
|||
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
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the MongoQueryProvider class.
|
|||
/// </summary>
|
|||
public MongoQueryProvider( |
|||
MongoCollection collection |
|||
) { |
|||
if (collection == null) { |
|||
throw new ArgumentNullException("collection"); |
|||
} |
|||
this.collection = collection; |
|||
} |
|||
#endregion
|
|||
|
|||
#region private static methods
|
|||
private static Func<MongoQueryProvider, Expression, IQueryable> GetCreateQueryDelegate( |
|||
Type type |
|||
) { |
|||
lock (staticLock) { |
|||
Func<MongoQueryProvider, Expression, IQueryable> createQueryDelegate; |
|||
if (!createQueryDelegates.TryGetValue(type, out createQueryDelegate)) { |
|||
var createQueryMethodInfo = createQueryGenericMethodDefinition.MakeGenericMethod(type); |
|||
|
|||
// lambdaExpression = (provider, expression) => (IQueryable) provider.CreateQuery<T>(expression)
|
|||
var providerParameter = Expression.Parameter(typeof(MongoQueryProvider), "provider"); |
|||
var expressionParameter = Expression.Parameter(typeof(Expression), "expression"); |
|||
var lambdaExpression = Expression.Lambda<Func<MongoQueryProvider, Expression, IQueryable>>( |
|||
Expression.Convert( |
|||
Expression.Call(providerParameter, createQueryMethodInfo, expressionParameter), |
|||
typeof(IQueryable) |
|||
), |
|||
providerParameter, |
|||
expressionParameter |
|||
); |
|||
createQueryDelegate = lambdaExpression.Compile(); |
|||
createQueryDelegates.Add(type, createQueryDelegate); |
|||
} |
|||
return createQueryDelegate; |
|||
} |
|||
} |
|||
|
|||
private static Func<MongoQueryProvider, Expression, object> GetExecuteDelegate( |
|||
Type type |
|||
) { |
|||
lock (staticLock) { |
|||
Func<MongoQueryProvider, Expression, object> executeDelegate; |
|||
if (!executeDelegates.TryGetValue(type, out executeDelegate)) { |
|||
var executeMethodInfo = executeGenericMethodDefinition.MakeGenericMethod(type); |
|||
|
|||
// lambdaExpression = (provider, expression) => (object) provider.Execute<T>(expression)
|
|||
var providerParameter = Expression.Parameter(typeof(MongoQueryProvider), "provider"); |
|||
var expressionParameter = Expression.Parameter(typeof(Expression), "expression"); |
|||
var lambdaExpression = Expression.Lambda<Func<MongoQueryProvider, Expression, object>>( |
|||
Expression.Convert( |
|||
Expression.Call(providerParameter, executeMethodInfo, expressionParameter), |
|||
typeof(object) |
|||
), |
|||
providerParameter, |
|||
expressionParameter |
|||
); |
|||
executeDelegate = lambdaExpression.Compile(); |
|||
executeDelegates.Add(type, executeDelegate); |
|||
} |
|||
return executeDelegate; |
|||
} |
|||
} |
|||
#endregion
|
|||
|
|||
#region public methods
|
|||
/// <summary>
|
|||
/// Creates a new instance of MongoQueryable{{T}} for this provider.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of the returned elements.</typeparam>
|
|||
/// <param name="expression">The query expression.</param>
|
|||
/// <returns>A new instance of MongoQueryable{{T}}.</returns>
|
|||
public IQueryable<T> CreateQuery<T>( |
|||
Expression expression |
|||
) { |
|||
if (expression == null) { |
|||
throw new ArgumentNullException("expression"); |
|||
} |
|||
if (!typeof(IQueryable<T>).IsAssignableFrom(expression.Type)) { |
|||
throw new ArgumentOutOfRangeException("expression"); |
|||
} |
|||
return new MongoQueryable<T>(this, expression); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a new instance MongoQueryable{{T}} for this provider. Calls the generic CreateQuery{{T}}
|
|||
/// to actually create the new MongoQueryable{{T}} instance.
|
|||
/// </summary>
|
|||
/// <param name="expression">The query expression.</param>
|
|||
/// <returns>A new instance of MongoQueryable{{T}}.</returns>
|
|||
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; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Executes a query.
|
|||
/// </summary>
|
|||
/// <typeparam name="TResult">The type of the result.</typeparam>
|
|||
/// <param name="expression">The query expression.</param>
|
|||
/// <returns>The result of the query.</returns>
|
|||
public TResult Execute<TResult>( |
|||
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(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Executes a query. Calls the generic method Execute{{T}} to actually execute the query.
|
|||
/// </summary>
|
|||
/// <param name="expression">The query expression.</param>
|
|||
/// <returns>The result of the query.</returns>
|
|||
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; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets an enumerator by executing the query.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">Type element type.</typeparam>
|
|||
/// <param name="expression">The LINQ expression.</param>
|
|||
/// <returns>An enumerator for the results of the query.</returns>
|
|||
public IEnumerator<T> GetEnumerator<T>( |
|||
Expression expression |
|||
) { |
|||
if (expression == null) { |
|||
throw new ArgumentNullException("expression"); |
|||
} |
|||
if (!typeof(IEnumerable<T>).IsAssignableFrom(expression.Type)) { |
|||
throw new ArgumentException("Argument expression is not valid."); |
|||
} |
|||
var translatedQuery = MongoLinqTranslator.Translate(collection, expression); |
|||
return translatedQuery.GetEnumerator<T>(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a string representation of the LINQ expression translated to a MongoDB query.
|
|||
/// </summary>
|
|||
/// <param name="expression">The LINQ expression.</param>
|
|||
/// <returns>A string.</returns>
|
|||
public string GetQueryText( |
|||
Expression expression |
|||
) { |
|||
var translatedQuery = MongoLinqTranslator.Translate(collection, expression); |
|||
return translatedQuery.ToString(); |
|||
} |
|||
#endregion
|
|||
} |
|||
} |
@ -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 { |
|||
/// <summary>
|
|||
/// An implementation of IQueryable{{T}} for querying a MongoDB collection.
|
|||
/// </summary>
|
|||
public class MongoQueryable<T> : IOrderedQueryable<T> { |
|||
#region private fields
|
|||
private MongoQueryProvider provider; |
|||
private Expression expression; |
|||
#endregion
|
|||
|
|||
#region constructors
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the MongoQueryable class.
|
|||
/// </summary>
|
|||
public MongoQueryable( |
|||
MongoQueryProvider provider |
|||
) { |
|||
if (provider == null) { |
|||
throw new ArgumentNullException("provider"); |
|||
} |
|||
this.provider = provider; |
|||
this.expression = Expression.Constant(this); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the MongoQueryable class.
|
|||
/// </summary>
|
|||
public MongoQueryable( |
|||
MongoQueryProvider provider, |
|||
Expression expression |
|||
) { |
|||
if (provider == null) { |
|||
throw new ArgumentNullException("provider"); |
|||
} |
|||
if (expression == null) { |
|||
throw new ArgumentNullException("expression"); |
|||
} |
|||
if (!typeof(IQueryable<T>).IsAssignableFrom(expression.Type)) { |
|||
throw new ArgumentOutOfRangeException("expression"); |
|||
} |
|||
this.provider = provider; |
|||
this.expression = expression; |
|||
} |
|||
#endregion
|
|||
|
|||
#region public methods
|
|||
/// <summary>
|
|||
/// Gets an enumerator for the results of a MongoDB LINQ query.
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
public IEnumerator<T> GetEnumerator() { |
|||
return provider.GetEnumerator<T>(expression); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a string representation of the MongoDB query obtained by translating the LINQ query.
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
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
|
|||
} |
|||
} |
@ -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; |
|||
} |
|||
} |
|||
} |
@ -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<C> collection; |
|||
|
|||
[TestFixtureSetUp] |
|||
public void Setup() { |
|||
server = MongoServer.Create("mongodb://localhost/?safe=true"); |
|||
server.Connect(); |
|||
database = server["onlinetests"]; |
|||
collection = database.GetCollection<C>("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<C>() |
|||
where c.X == 1 |
|||
select c; |
|||
var count = 0; |
|||
foreach (var c in query) { |
|||
Assert.AreEqual(1, c.X); |
|||
count++; |
|||
} |
|||
Assert.AreEqual(1, count); |
|||
} |
|||
} |
|||
} |
@ -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<C>().Expression; |
|||
var provider = new MongoQueryProvider(collection); |
|||
var query = provider.CreateQuery<C>(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<C>().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); |
|||
} |
|||
} |
|||
} |
@ -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<C>(provider); |
|||
Assert.AreSame(typeof(C), iqueryable.ElementType); |
|||
Assert.AreSame(provider, iqueryable.Provider); |
|||
} |
|||
|
|||
[Test] |
|||
public void TestConstructorWithTwoArguments() { |
|||
var queryable = collection.AsQueryable<C>(); |
|||
var iqueryable = (IQueryable) new MongoQueryable<C>((MongoQueryProvider) queryable.Provider, queryable.Expression); |
|||
Assert.AreSame(typeof(C), iqueryable.ElementType); |
|||
Assert.AreSame(queryable.Provider, iqueryable.Provider); |
|||
Assert.AreSame(queryable.Expression, iqueryable.Expression); |
|||
} |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue