|
|
|
@ -0,0 +1,134 @@
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Connected.Expressions;
|
|
|
|
|
using Connected.Data.Sql;
|
|
|
|
|
using Connected.Expressions.Translation;
|
|
|
|
|
using System.Linq.Expressions;
|
|
|
|
|
using Connected.Data.Storage;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using Connected.Entities;
|
|
|
|
|
|
|
|
|
|
namespace Connected.Data.Tests.Translation;
|
|
|
|
|
|
|
|
|
|
[TestClass]
|
|
|
|
|
public class TranslatorTests
|
|
|
|
|
{
|
|
|
|
|
[TestMethod]
|
|
|
|
|
public void Translator_GeneratesBasicSelectExpression_UsingTSQL()
|
|
|
|
|
{
|
|
|
|
|
var context = new ExpressionCompilationContext(new TSqlLanguage());
|
|
|
|
|
|
|
|
|
|
var translator = new Translator(context);
|
|
|
|
|
|
|
|
|
|
var data = SampleData.All();
|
|
|
|
|
|
|
|
|
|
var dataQueryable = data.AsQueryable();
|
|
|
|
|
|
|
|
|
|
var query = (from x in dataQueryable select x);
|
|
|
|
|
|
|
|
|
|
var operatorMethodInfo = QueryableMethods.SingleOrDefaultWithoutPredicate;
|
|
|
|
|
|
|
|
|
|
if (operatorMethodInfo.IsGenericMethod)
|
|
|
|
|
{
|
|
|
|
|
operatorMethodInfo = operatorMethodInfo.GetGenericArguments().Length == 2
|
|
|
|
|
? operatorMethodInfo.MakeGenericMethod(typeof(DummyEntity), typeof(DummyEntity).GetGenericArguments().Single())
|
|
|
|
|
: operatorMethodInfo.MakeGenericMethod(typeof(DummyEntity));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var expr = Expression.Call(instance: null, method: operatorMethodInfo, arguments: new[] { query.Expression });
|
|
|
|
|
|
|
|
|
|
var result = translator.Translate(expr) as ProjectionExpression;
|
|
|
|
|
|
|
|
|
|
var select = result.Select;
|
|
|
|
|
|
|
|
|
|
Assert.IsInstanceOfType(select, typeof(SelectExpression));
|
|
|
|
|
Assert.IsInstanceOfType(select.From, typeof(TableExpression));
|
|
|
|
|
Assert.IsNull(select.Where, "Where should be null");
|
|
|
|
|
Assert.IsNull(select.Take, "Take should be null");
|
|
|
|
|
Assert.IsNull(select.Skip, "Skip should be null");
|
|
|
|
|
Assert.AreEqual(0, select.GroupBy.Count);
|
|
|
|
|
Assert.IsFalse(select.IsReverse);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[TestMethod]
|
|
|
|
|
public void Translator_GeneratesSelectExpression_WithWhere_UsingTSQL()
|
|
|
|
|
{
|
|
|
|
|
var context = new ExpressionCompilationContext(new TSqlLanguage());
|
|
|
|
|
|
|
|
|
|
var translator = new Translator(context);
|
|
|
|
|
|
|
|
|
|
var data = SampleData.All();
|
|
|
|
|
|
|
|
|
|
var dataQueryable = data.AsQueryable();
|
|
|
|
|
|
|
|
|
|
var query = (from x in dataQueryable where x.Id == 1 select x);
|
|
|
|
|
|
|
|
|
|
var operatorMethodInfo = QueryableMethods.SingleOrDefaultWithoutPredicate;
|
|
|
|
|
|
|
|
|
|
if (operatorMethodInfo.IsGenericMethod)
|
|
|
|
|
{
|
|
|
|
|
operatorMethodInfo = operatorMethodInfo.GetGenericArguments().Length == 2
|
|
|
|
|
? operatorMethodInfo.MakeGenericMethod(typeof(DummyEntity), typeof(DummyEntity).GetGenericArguments().Single())
|
|
|
|
|
: operatorMethodInfo.MakeGenericMethod(typeof(DummyEntity));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var expr = Expression.Call(instance: null, method: operatorMethodInfo, arguments: new[] { query.Expression });
|
|
|
|
|
|
|
|
|
|
var result = translator.Translate(expr) as ProjectionExpression;
|
|
|
|
|
|
|
|
|
|
var select = result.Select;
|
|
|
|
|
|
|
|
|
|
Assert.IsInstanceOfType(select, typeof(SelectExpression));
|
|
|
|
|
Assert.IsInstanceOfType(select.From, typeof(TableExpression));
|
|
|
|
|
Assert.IsNotNull(select.Where, "Where should not be null");
|
|
|
|
|
Assert.IsNull(select.Take, "Take should be null");
|
|
|
|
|
Assert.IsNull(select.Skip, "Skip should be null");
|
|
|
|
|
Assert.AreEqual(0, select.GroupBy.Count);
|
|
|
|
|
Assert.IsFalse(select.IsReverse);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public record DummyEntity : Entity<long>;
|
|
|
|
|
|
|
|
|
|
internal static class SampleData
|
|
|
|
|
{
|
|
|
|
|
public static List<DummyEntity> All()
|
|
|
|
|
{
|
|
|
|
|
return new List<DummyEntity>
|
|
|
|
|
{
|
|
|
|
|
new DummyEntity{ Id = 1},
|
|
|
|
|
new DummyEntity{ Id = 2},
|
|
|
|
|
new DummyEntity{ Id = 3},
|
|
|
|
|
new DummyEntity{ Id = 4},
|
|
|
|
|
new DummyEntity{ Id = 5}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static class QueryableMethods
|
|
|
|
|
{
|
|
|
|
|
static QueryableMethods()
|
|
|
|
|
{
|
|
|
|
|
var queryableMethodGroups = typeof(Queryable)
|
|
|
|
|
.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly)
|
|
|
|
|
.GroupBy(mi => mi.Name)
|
|
|
|
|
.ToDictionary(e => e.Key, l => l.ToList());
|
|
|
|
|
|
|
|
|
|
SingleWithoutPredicate = GetMethod(nameof(Queryable.Single), 1, types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) });
|
|
|
|
|
SingleOrDefaultWithoutPredicate = GetMethod(nameof(Queryable.SingleOrDefault), 1, types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) });
|
|
|
|
|
|
|
|
|
|
MethodInfo GetMethod(string name, int genericParameterCount, Func<Type[], Type[]> parameterGenerator)
|
|
|
|
|
{
|
|
|
|
|
return queryableMethodGroups[name].Single(mi => ((genericParameterCount == 0 && !mi.IsGenericMethod)
|
|
|
|
|
|| (mi.IsGenericMethod && mi.GetGenericArguments().Length == genericParameterCount))
|
|
|
|
|
&& mi.GetParameters().Select(e => e.ParameterType).SequenceEqual(parameterGenerator(mi.IsGenericMethod ? mi.GetGenericArguments() : Array.Empty<Type>())));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static MethodInfo SingleWithoutPredicate { get; }
|
|
|
|
|
public static MethodInfo SingleOrDefaultWithoutPredicate { get; }
|
|
|
|
|
}
|