diff --git a/Musoq.Evaluator.Tests/CrossApplyCteTests.cs b/Musoq.Evaluator.Tests/CrossApplyCteTests.cs index c8de47c..b313731 100644 --- a/Musoq.Evaluator.Tests/CrossApplyCteTests.cs +++ b/Musoq.Evaluator.Tests/CrossApplyCteTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using Musoq.Evaluator.Tests.Schema.Generic; @@ -35,6 +36,11 @@ private class CrossApplyClass3 public string[] Skills { get; set; } } + public class CrossApplyClass4 + { + public string Name { get; set; } + } + [TestMethod] public void WhenSchemaMethodCrossAppliedWithAnotherSchema_WithinCte_ShouldPass() { @@ -320,4 +326,45 @@ with first as ( Assert.AreEqual("Name3", table[8].Values[0]); Assert.AreEqual("Skill9", table[8].Values[1]); } + + [TestMethod] + public void WhenCrossApplyComponentsMustInjectMultipleEntities_ShouldNotThrow() + { + var query = """ + with first as ( + select + r.AggregateValues(r.Name) as Name1, + r.AggregateValues(r.Name) as Name2 + from #schema.first() r + cross apply r.JustReturnArrayOfString() b + cross apply r.JustReturnArrayOfString() c + group by 'fake' + ) + select + b.Name1, + b.Name2, + p.Value + from first b + inner join #schema.first() r on 1 = 1 + cross apply r.MethodArrayOfStrings(r.TestMethodWithInjectEntityAndParameter(b.Name1), r.TestMethodWithInjectEntityAndParameter(b.Name2)) p + """; + + var firstSource = new List + { + new() {Name = "Name1"} + }.ToArray(); + + var vm = CreateAndRunVirtualMachine( + query, + firstSource); + + try + { + vm.Run(); + } + catch (Exception) + { + Assert.Fail($"Expected not to throw exception but got: "); + } + } } \ No newline at end of file diff --git a/Musoq.Evaluator.Tests/MethodInvocationTests.cs b/Musoq.Evaluator.Tests/MethodInvocationTests.cs index 1cf872f..82341b3 100644 --- a/Musoq.Evaluator.Tests/MethodInvocationTests.cs +++ b/Musoq.Evaluator.Tests/MethodInvocationTests.cs @@ -235,8 +235,8 @@ cross apply x.JustReturnArrayOfString() b select p.Value from first b - inner join #A.entities() r2 on 1 = 1 - cross apply r2.MethodArrayOfStrings(r2.TestMethodWithInjectEntityAndParameter(b.Name), r2.TestMethodWithInjectEntityAndParameter(b.Name)) p + inner join #A.entities() r on 1 = 1 + cross apply r.MethodArrayOfStrings(r.TestMethodWithInjectEntityAndParameter(b.Name), r.TestMethodWithInjectEntityAndParameter(b.Name)) p """; var sources = new Dictionary>() diff --git a/Musoq.Evaluator.Tests/Schema/Generic/GenericLibrary.cs b/Musoq.Evaluator.Tests/Schema/Generic/GenericLibrary.cs index aefe7ed..4c18b18 100644 --- a/Musoq.Evaluator.Tests/Schema/Generic/GenericLibrary.cs +++ b/Musoq.Evaluator.Tests/Schema/Generic/GenericLibrary.cs @@ -1,5 +1,28 @@ using Musoq.Plugins; +using Musoq.Plugins.Attributes; namespace Musoq.Evaluator.Tests.Schema.Generic; -public class GenericLibrary : LibraryBase; \ No newline at end of file +public class GenericLibrary : LibraryBase +{ + [BindableMethod] + public string[] JustReturnArrayOfString() + { + return ["1", "2", "3"]; + } + + [BindableMethod] + public string TestMethodWithInjectEntityAndParameter(string name) + { + return name; + } + + [BindableMethod] + public string[] MethodArrayOfStrings([InjectSpecificSource(typeof(object))] TEntity entity, string name1, string name2) + { + return [ + name1, + name2 + ]; + } +} \ No newline at end of file diff --git a/Musoq.Evaluator/Musoq.Evaluator.csproj b/Musoq.Evaluator/Musoq.Evaluator.csproj index 533e465..e34e939 100644 --- a/Musoq.Evaluator/Musoq.Evaluator.csproj +++ b/Musoq.Evaluator/Musoq.Evaluator.csproj @@ -3,7 +3,7 @@ net8.0 true - 7.5.1 + 7.5.2 Jakub Puchała Musoq https://github.com/Puchaczov/Musoq diff --git a/Musoq.Evaluator/Tables/TableRowSource.cs b/Musoq.Evaluator/Tables/TableRowSource.cs index 1ba8f24..012a46f 100644 --- a/Musoq.Evaluator/Tables/TableRowSource.cs +++ b/Musoq.Evaluator/Tables/TableRowSource.cs @@ -6,14 +6,16 @@ namespace Musoq.Evaluator.Tables; public class TableRowSource : RowSource { + private static readonly object[] DiscardedContexts = [new DiscardedRowContext()]; + private readonly IDictionary _columnToIndexMap; private readonly Table _table; - private readonly bool _skipContext; + private readonly bool _discardedContext; - public TableRowSource(Table rowSource, bool skipContext) + public TableRowSource(Table rowSource, bool discardContext) { _table = rowSource; - _skipContext = skipContext; + _discardedContext = discardContext; _columnToIndexMap = new Dictionary(); @@ -21,11 +23,13 @@ public TableRowSource(Table rowSource, bool skipContext) _columnToIndexMap.Add(column.ColumnName, column.ColumnIndex); } - public override IEnumerable Rows => _skipContext ? RowsWithSkippedContexts : RowsWithContexts; + public override IEnumerable Rows => _discardedContext ? RowsWithDiscardedContexts : RowsWithContexts; private IEnumerable RowsWithContexts => _table.Select(row => new RowResolver((ObjectsRow)row, _columnToIndexMap)); - private IEnumerable RowsWithSkippedContexts => - _table.Select(row => new RowResolver(new ObjectsRow(row.Values, row.Values), _columnToIndexMap)); + private IEnumerable RowsWithDiscardedContexts => + _table.Select(row => new RowResolver(new ObjectsRow(row.Values, DiscardedContexts), _columnToIndexMap)); + + private class DiscardedRowContext; } \ No newline at end of file diff --git a/Musoq.Evaluator/Visitors/BuildMetadataAndInferTypesVisitor.cs b/Musoq.Evaluator/Visitors/BuildMetadataAndInferTypesVisitor.cs index 15fb014..57fcf2b 100644 --- a/Musoq.Evaluator/Visitors/BuildMetadataAndInferTypesVisitor.cs +++ b/Musoq.Evaluator/Visitors/BuildMetadataAndInferTypesVisitor.cs @@ -1482,8 +1482,11 @@ private void VisitAccessMethod(AccessMethodNode node, Func(); @@ -2090,6 +2093,10 @@ private static bool TryConstructGenericMethod(MethodInfo methodInfo, ArgsListNod { i = 1; shiftArgsWhenInjectSpecificSourcePresent = 1; + if ((genericArgument.IsGenericParameter || genericArgument.IsGenericMethodParameter) && parameters[0].ParameterType.IsGenericParameter) + { + genericArgumentsDistinct.Add(entity); + } } for (; i < parameters.Length; i++) { @@ -2138,7 +2145,7 @@ private static bool TryConstructGenericMethod(MethodInfo methodInfo, ArgsListNod } var genericArgumentsConcreteTypes = genericArgumentsDistinct.Distinct().ToArray(); - + constructedMethod = methodInfo.MakeGenericMethod(genericArgumentsConcreteTypes); return true; } diff --git a/Musoq.Evaluator/Visitors/RewriteQueryVisitor.cs b/Musoq.Evaluator/Visitors/RewriteQueryVisitor.cs index e1408ae..c468149 100644 --- a/Musoq.Evaluator/Visitors/RewriteQueryVisitor.cs +++ b/Musoq.Evaluator/Visitors/RewriteQueryVisitor.cs @@ -463,8 +463,6 @@ public void Visit(QueryNode node) var scoreWhere = where; var scoreOrderBy = orderBy; - QueryNode query; - var splitNodes = new List(); var source = from.Alias.ToRowsSource().WithRowsUsage(); @@ -860,7 +858,7 @@ public void Visit(QueryNode node) modifiedOrderBy = new OrderByNode(splitOrderBy); } - query = new DetailedQueryNode( + QueryNode query = new DetailedQueryNode( outSelect, new Parser.ExpressionFromNode( new InMemoryGroupedFromNode(returnScore)), @@ -887,8 +885,6 @@ public void Visit(QueryNode node) if (IsQueryWithMixedAggregateAndNonAggregateMethods(split)) { - query = new InternalQueryNode(select, from, where, null, orderBy, skip, take, - CreateRefreshMethods(usedRefreshMethods)); throw new NotImplementedException("Mixing aggregate and non aggregate methods is not implemented yet"); } diff --git a/Musoq.Evaluator/Visitors/ToCSharpRewriteTreeVisitor.cs b/Musoq.Evaluator/Visitors/ToCSharpRewriteTreeVisitor.cs index 50c15a4..69348f0 100644 --- a/Musoq.Evaluator/Visitors/ToCSharpRewriteTreeVisitor.cs +++ b/Musoq.Evaluator/Visitors/ToCSharpRewriteTreeVisitor.cs @@ -680,6 +680,7 @@ public void Visit(AccessMethodNode node) (IndexBasedContextsPositionsSymbol) _scope.ScopeSymbolTable.GetSymbol(MetaAttributes .PreformatedContexts); var orderNumber = int.Parse(_scope[MetaAttributes.OrderNumber]); + currentContext = preformattedContexts.GetIndexFor(orderNumber, node.Alias); } else @@ -2067,7 +2068,7 @@ public void Visit(InMemoryTableFromNode node) _inMemoryTableIndexes[ node.VariableName]))))))); - var literalFalseArgument = SyntaxFactory.Argument( + var literalTrueArgument = SyntaxFactory.Argument( SyntaxFactory.LiteralExpression( SyntaxKind.TrueLiteralExpression)); @@ -2084,7 +2085,7 @@ public void Visit(InMemoryTableFromNode node) SyntaxFactory.ArgumentList( SyntaxFactory.SeparatedList([ tableArgument, - literalFalseArgument + literalTrueArgument ]))))))))); }