blob: 6582c92802b830665eb830630213f6f318bfd161 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
namespace Apache.Ignite.Linq
{
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using Apache.Ignite.Core.Cache.Query;
using Apache.Ignite.Core.Impl.Common;
using Apache.Ignite.Linq.Impl;
/// <summary>
/// Delegate for compiled query with arbitrary number of arguments.
/// </summary>
/// <typeparam name="T">Result type.</typeparam>
/// <param name="args">The arguments.</param>
/// <returns>Query cursor.</returns>
public delegate IQueryCursor<T> CompiledQueryFunc<T>(params object[] args);
/// <summary>
/// Represents a compiled cache query.
/// </summary>
public static class CompiledQuery
{
/// <summary>
/// Creates a new delegate that represents the compiled cache query.
/// </summary>
/// <param name="query">The query to compile.</param>
/// <returns>Delegate that represents the compiled cache query.</returns>
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0",
Justification = "Invalid warning, validation is present.")]
public static Func<IQueryCursor<T>> Compile<T>(Expression<Func<IQueryable<T>>> query)
{
IgniteArgumentCheck.NotNull(query, "query");
var compiledQuery = GetCompiledQuery<T>(query);
return () => compiledQuery(new object[0]);
}
/// <summary>
/// Creates a new delegate that represents the compiled cache query with any number of arguments.
/// <para />
/// This method differs from other Compile methods in that it takes in <see cref="ICacheQueryable"/> directly,
/// and returns a delegate that takes an array of parameters.
/// It is up to the user to provide query arguments in correct order.
/// <para />
/// This method also imposes no restrictions on where the query comes from (in contrary to other methods).
/// </summary>
/// <param name="query">The query to compile.</param>
/// <returns>Delegate that represents the compiled cache query.</returns>
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0",
Justification = "Invalid warning, validation is present.")]
public static CompiledQueryFunc<T> Compile<T>(IQueryable<T> query)
{
IgniteArgumentCheck.NotNull(query, "query");
var cacheQueryable = query as ICacheQueryableInternal;
if (cacheQueryable == null)
throw GetInvalidQueryException(query);
var compileQuery = cacheQueryable.CompileQuery<T>();
// Special delegate is required to allow params[].
return args => compileQuery(args);
}
/// <summary>
/// Creates a new delegate that represents the compiled cache query.
/// </summary>
/// <param name="query">The query to compile.</param>
/// <returns>Delegate that represents the compiled cache query.</returns>
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0",
Justification = "Invalid warning, validation is present.")]
public static Func<T1, IQueryCursor<T>> Compile<T, T1>(Expression<Func<T1, IQueryable<T>>> query)
{
IgniteArgumentCheck.NotNull(query, "query");
var compiledQuery = GetCompiledQuery<T>(query);
return x => compiledQuery(new object[] {x});
}
/// <summary>
/// Creates a new delegate that represents the compiled cache query.
/// </summary>
/// <param name="query">The query to compile.</param>
/// <returns>Delegate that represents the compiled cache query.</returns>
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0",
Justification = "Invalid warning, validation is present.")]
public static Func<T1, T2, IQueryCursor<T>> Compile<T, T1, T2>(Expression<Func<T1, T2,
IQueryable<T>>> query)
{
IgniteArgumentCheck.NotNull(query, "query");
var compiledQuery = GetCompiledQuery<T>(query);
return (x, y) => compiledQuery(new object[] {x, y});
}
/// <summary>
/// Creates a new delegate that represents the compiled cache query.
/// </summary>
/// <param name="query">The query to compile.</param>
/// <returns>Delegate that represents the compiled cache query.</returns>
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0",
Justification = "Invalid warning, validation is present.")]
public static Func<T1, T2, T3, IQueryCursor<T>> Compile<T, T1, T2, T3>(Expression<Func<T1, T2, T3,
IQueryable<T>>> query)
{
IgniteArgumentCheck.NotNull(query, "query");
var compiledQuery = GetCompiledQuery<T>(query);
return (x, y, z) => compiledQuery(new object[] {x, y, z});
}
/// <summary>
/// Creates a new delegate that represents the compiled cache query.
/// </summary>
/// <param name="query">The query to compile.</param>
/// <returns>Delegate that represents the compiled cache query.</returns>
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0",
Justification = "Invalid warning, validation is present.")]
public static Func<T1, T2, T3, T4, IQueryCursor<T>> Compile<T, T1, T2, T3, T4>(Expression<Func<T1, T2, T3, T4,
IQueryable<T>>> query)
{
IgniteArgumentCheck.NotNull(query, "query");
var compiledQuery = GetCompiledQuery<T>(query);
return (x, y, z, a) => compiledQuery(new object[] {x, y, z, a});
}
/// <summary>
/// Creates a new delegate that represents the compiled cache query.
/// </summary>
/// <param name="query">The query to compile.</param>
/// <returns>Delegate that represents the compiled cache query.</returns>
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0",
Justification = "Invalid warning, validation is present.")]
public static Func<T1, T2, T3, T4, T5, IQueryCursor<T>> Compile<T, T1, T2, T3, T4, T5>(
Expression<Func<T1, T2, T3, T4, T5, IQueryable<T>>> query)
{
IgniteArgumentCheck.NotNull(query, "query");
var compiledQuery = GetCompiledQuery<T>(query);
return (x, y, z, a, b) => compiledQuery(new object[] {x, y, z, a, b});
}
/// <summary>
/// Creates a new delegate that represents the compiled cache query.
/// </summary>
/// <param name="query">The query to compile.</param>
/// <returns>Delegate that represents the compiled cache query.</returns>
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0",
Justification = "Invalid warning, validation is present.")]
public static Func<T1, T2, T3, T4, T5, T6, IQueryCursor<T>> Compile<T, T1, T2, T3, T4, T5, T6>(
Expression<Func<T1, T2, T3, T4, T5, T6, IQueryable<T>>> query)
{
IgniteArgumentCheck.NotNull(query, "query");
var compiledQuery = GetCompiledQuery<T>(query);
return (x, y, z, a, b, c) => compiledQuery(new object[] {x, y, z, a, b, c});
}
/// <summary>
/// Creates a new delegate that represents the compiled cache query.
/// </summary>
/// <param name="query">The query to compile.</param>
/// <returns>Delegate that represents the compiled cache query.</returns>
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0",
Justification = "Invalid warning, validation is present.")]
public static Func<T1, T2, T3, T4, T5, T6, T7, IQueryCursor<T>> Compile<T, T1, T2, T3, T4, T5, T6, T7>(
Expression<Func<T1, T2, T3, T4, T5, T6, T7, IQueryable<T>>> query)
{
IgniteArgumentCheck.NotNull(query, "query");
var compiledQuery = GetCompiledQuery<T>(query);
return (x, y, z, a, b, c, d) => compiledQuery(new object[] {x, y, z, a, b, c, d});
}
/// <summary>
/// Creates a new delegate that represents the compiled cache query.
/// </summary>
/// <param name="query">The query to compile.</param>
/// <returns>Delegate that represents the compiled cache query.</returns>
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0",
Justification = "Invalid warning, validation is present.")]
public static Func<T1, T2, T3, T4, T5, T6, T7, T8, IQueryCursor<T>> Compile<T, T1, T2, T3, T4, T5, T6, T7, T8>(
Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, IQueryable<T>>> query)
{
IgniteArgumentCheck.NotNull(query, "query");
var compiledQuery = GetCompiledQuery<T>(query);
return (x, y, z, a, b, c, d, e) => compiledQuery(new object[] {x, y, z, a, b, c, d, e});
}
/// <summary>
/// Gets the compiled query.
/// </summary>
private static Func<object[], IQueryCursor<T>> GetCompiledQuery<T>(LambdaExpression expression)
{
Debug.Assert(expression != null);
// Get default parameter values.
var paramValues = expression.Parameters
.Select(x => x.Type)
.Select(x => x.IsValueType ? Activator.CreateInstance(x) : null)
.ToArray();
var transformingxpressionVisitor = new JoinInnerSequenceParameterNotNullExpressionVisitor();
var queryCaller = (LambdaExpression)transformingxpressionVisitor.Visit(expression);
// Compile and invoke the delegate to obtain the cacheQueryable.
var queryable = queryCaller.Compile().DynamicInvoke(paramValues);
var cacheQueryable = queryable as ICacheQueryableInternal;
if (cacheQueryable == null)
throw GetInvalidQueryException(queryable);
return cacheQueryable.CompileQuery<T>(expression);
}
/// <summary>
/// Gets the invalid query exception.
/// </summary>
private static ArgumentException GetInvalidQueryException(object queryable)
{
return new ArgumentException(
string.Format("{0} can only compile cache queries produced by AsCacheQueryable method. " +
"Provided query is not valid: '{1}'", typeof(CompiledQuery).FullName, queryable));
}
}
}