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
-
29Bson/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