Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1. Fixed cross apply crashed during runtime while trying to inject or… #88

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions Musoq.Evaluator.Tests/AliasTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,120 @@ with p as (
Assert.AreEqual("q.p.first.FirstItem", table.Columns.ElementAt(0).ColumnName);
Assert.AreEqual("q.p.second.FirstItem", table.Columns.ElementAt(1).ColumnName);
}

[TestMethod]
public void WhenAliasUsedWithinCte_AndSameUsedWithinOuterQuery_AliasesShouldNotClash()
{
const string query = @"
with p as (
select
1
from #schema.first() first
cross apply first.Split('') b
)
select
1
from p inner join #schema.first() first on 1 = 1
cross apply first.Split('') b";

var vm = CreateAndRunVirtualMachine(query, [
new()
], [
new()
]);

var table = vm.Run();

Assert.AreEqual(1, table.Columns.Count());

Assert.AreEqual("1", table.Columns.ElementAt(0).ColumnName);
}

[TestMethod]
public void WhenSameAliasUsedInFromAndJoin_ShouldThrow()
{
const string query = "select a.FirstItem from #schema.first() a inner join #schema.second() a on a.FirstItem = a.FirstItem";

Assert.ThrowsException<AliasAlreadyUsedException>(() => CreateAndRunVirtualMachine(query, [
new(),
new()
], [
new(),
new()
]));
}

[TestMethod]
public void WhenSameAliasUsedInMultipleJoins_ShouldThrow()
{
const string query = @"
select src.FirstItem
from #schema.first() src
inner join #schema.second() b on src.FirstItem = b.FirstItem
inner join #schema.third() b on b.FirstItem = src.FirstItem";

Assert.ThrowsException<AliasAlreadyUsedException>(() => CreateAndRunVirtualMachine(query, [
new(),
new(),
new()
], [
new(),
new(),
new()
]));
}

[TestMethod]
public void WhenSameAliasUsedInCTEAndMainQuery_ShouldThrow()
{
const string query = @"
with src as (
select FirstItem from #schema.first()
)
select src.FirstItem
from #schema.second() src
inner join src on src.FirstItem = src.FirstItem";

Assert.ThrowsException<AliasAlreadyUsedException>(() => CreateAndRunVirtualMachine(query, [
new(),
new()
], [
new(),
new()
]));
}

[TestMethod]
public void WhenSameAliasUsedInCrossApply_ShouldThrow()
{
const string query = @"
select a.FirstItem
from #schema.first() a
cross apply #schema.second() a";

Assert.ThrowsException<AliasAlreadyUsedException>(() => CreateAndRunVirtualMachine(query, [
new(),
new()
], [
new(),
new()
]));
}

[TestMethod]
public void WhenSameAliasUsedInOuterApply_ShouldThrow()
{
const string query = @"
select a.FirstItem
from #schema.first() a
outer apply #schema.second() a";

Assert.ThrowsException<AliasAlreadyUsedException>(() => CreateAndRunVirtualMachine(query, [
new(),
new()
], [
new(),
new()
]));
}
}
6 changes: 5 additions & 1 deletion Musoq.Evaluator.Tests/CrossApplyMethodTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,11 @@ public void CrossApplyProperty_SplitStringToWords_ShouldPass()
[TestMethod]
public void CrossApplyProperty_MultipleSplitWords_ShouldPass()
{
const string query = "select b.Value, c.Value from #schema.first() a cross apply a.Split(a.Text, ' ') as b cross apply a.Split(a.Text, ' ') as c";
const string query = @"
select
b.Value,
c.Value
from #schema.first() a cross apply a.Split(a.Text, ' ') as b cross apply a.Split(a.Text, ' ') as c";

string[] words = ["Lorem", "ipsum", "dolor", "sit", "amet,", "consectetur", "adipiscing", "elit."];

Expand Down
37 changes: 37 additions & 0 deletions Musoq.Evaluator.Tests/MethodInvocationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,41 @@ public void WhenMethodCallDoesNotHaveAlias_ShouldThrows()

Assert.ThrowsException<AliasMissingException>(() => CreateAndRunVirtualMachine(query, sources));
}

[TestMethod]
public void WhenContextsOfInnerCteShouldTurnContextOfResultingTable_ShouldPass()
{
var query = """
with first as (
select
x.Name as Name
from #A.entities() x
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
""";

var sources = new Dictionary<string, IEnumerable<BasicEntity>>()
{
{
"#A", [
new BasicEntity("TEST")
]
}
};

var vm = CreateAndRunVirtualMachine(query, sources);

var table = vm.Run();

Assert.AreEqual(4, table.Count);
Assert.AreEqual("TEST", table[0].Values[0]);
Assert.AreEqual("TEST", table[1].Values[0]);
Assert.AreEqual("TEST", table[2].Values[0]);
Assert.AreEqual("TEST", table[3].Values[0]);
}
}
25 changes: 25 additions & 0 deletions Musoq.Evaluator.Tests/Schema/Basic/Library.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,31 @@ public string MyName([InjectSpecificSource(typeof(BasicEntity))] BasicEntity ent
{
return entity.Name;
}

[BindableMethod]
public string[] MethodArrayOfStrings([InjectSpecificSource(typeof(BasicEntity))] BasicEntity entity, string name1, string name2)
{
return [
name1,
name2
];
}

[BindableMethod]
public string TestMethodWithInjectEntityAndParameter([InjectSpecificSource(typeof(BasicEntity))] BasicEntity entity, string name)
{
return name;
}

[BindableMethod]
public string[] JustReturnArrayOfString()
{
return
[
"1",
"2"
];
}

[BindableMethod]
public string Extension([InjectSpecificSource(typeof(BasicEntity))] BasicEntity entity)
Expand Down
4 changes: 2 additions & 2 deletions Musoq.Evaluator/Helpers/EvaluationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ public static RowSource ConvertEnumerableToSource<T>(IEnumerable<T> enumerable)
return new GenericRowsSource<T>(enumerable);
}

public static RowSource ConvertTableToSource(Table table)
public static RowSource ConvertTableToSource(Table table, bool skipContext)
{
return new TableRowSource(table);
return new TableRowSource(table, skipContext);
}

public static RowSource ConvertTableToSource(List<Group> list)
Expand Down
14 changes: 12 additions & 2 deletions Musoq.Evaluator/Helpers/NamingHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,14 @@ public static string ToScoreTable(this string name)
return $"{name}Score";
}

public static string ToTransformedRowsSource(this string name)
public static string ToTransformedRowsSource(this string name, bool isForGrouping)
{
return $"{nameof(EvaluationHelper)}.{nameof(EvaluationHelper.ConvertTableToSource)}({name}).Rows";
if (isForGrouping)
{
return $"{nameof(EvaluationHelper)}.{nameof(EvaluationHelper.ConvertTableToSource)}({name}).Rows";
}

return $"{nameof(EvaluationHelper)}.{nameof(EvaluationHelper.ConvertTableToSource)}({name}, false).Rows";
}

public static string WithRowsUsage(this string name)
Expand All @@ -61,4 +66,9 @@ public static string ListOf<T>()
{
return $"List<{typeof(T).Name}>";
}

private static string GetSkipContextLiteral(bool skipContexts)
{
return skipContexts ? "true" : "false";
}
}
2 changes: 1 addition & 1 deletion Musoq.Evaluator/Musoq.Evaluator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>7.5.0</Version>
<Version>7.5.1</Version>
<Authors>Jakub Puchała</Authors>
<Product>Musoq</Product>
<PackageProjectUrl>https://github.com/Puchaczov/Musoq</PackageProjectUrl>
Expand Down
9 changes: 9 additions & 0 deletions Musoq.Evaluator/Resources/MetaAttributes.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Musoq.Evaluator/Resources/MetaAttributes.resx
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,7 @@
<data name="OrderNumber" xml:space="preserve">
<value>OrderNumber</value>
</data>
<data name="Aliases" xml:space="preserve">
<value>Aliases</value>
</data>
</root>
18 changes: 10 additions & 8 deletions Musoq.Evaluator/Tables/TableRowSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,24 @@ public class TableRowSource : RowSource
{
private readonly IDictionary<string, int> _columnToIndexMap;
private readonly Table _table;
private readonly bool _skipContext;

public TableRowSource(Table rowSource)
public TableRowSource(Table rowSource, bool skipContext)
{
_table = rowSource;
_skipContext = skipContext;

_columnToIndexMap = new Dictionary<string, int>();

foreach (var column in _table.Columns)
_columnToIndexMap.Add(column.ColumnName, column.ColumnIndex);
}

public TableRowSource(Table rowSource, IDictionary<string, int> columnToIndexMap)
{
_table = rowSource;
_columnToIndexMap = columnToIndexMap;
}

public override IEnumerable<IObjectResolver> Rows =>
public override IEnumerable<IObjectResolver> Rows => _skipContext ? RowsWithSkippedContexts : RowsWithContexts;

private IEnumerable<IObjectResolver> RowsWithContexts =>
_table.Select(row => new RowResolver((ObjectsRow)row, _columnToIndexMap));

private IEnumerable<IObjectResolver> RowsWithSkippedContexts =>
_table.Select(row => new RowResolver(new ObjectsRow(row.Values, row.Values), _columnToIndexMap));
}
24 changes: 24 additions & 0 deletions Musoq.Evaluator/Utils/SymbolTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ public void AddSymbol(object key, Symbol symbol)
{
_symbols.Add(key, symbol);
}

public TSymbol AddOrGetSymbol<TSymbol>(object key) where TSymbol : Symbol, new()
{
if (_symbols.TryGetValue(key, out var symbol) && symbol is TSymbol castedSymbol)
{
return castedSymbol;
}

var newSymbol = new TSymbol();
_symbols.Add(key, newSymbol);
return newSymbol;
}

public void AddSymbolIfNotExist(object key, Symbol symbol)
{
Expand All @@ -27,6 +39,18 @@ public TSymbol GetSymbol<TSymbol>(object key) where TSymbol : Symbol
return (TSymbol) GetSymbol(key);
}

public bool TryGetSymbol<TSymbol>(object key, out TSymbol symbol)
{
if (_symbols.TryGetValue(key, out var plainSymbol) && plainSymbol is TSymbol castedSymbol)
{
symbol = castedSymbol;
return true;
}

symbol = default;
return false;
}

public void MoveSymbol(object oldKey, object newKey)
{
_symbols.Add(newKey, GetSymbol(oldKey));
Expand Down
20 changes: 20 additions & 0 deletions Musoq.Evaluator/Utils/Symbols/AliasesSymbol.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Collections.Generic;
using Musoq.Parser.Nodes.From;
using Musoq.Schema;

namespace Musoq.Evaluator.Utils.Symbols;

public class AliasesSymbol : Symbol
{
private readonly HashSet<string> _aliases = [];

public void AddAlias(string alias)
{
_aliases.Add(alias);
}

public bool ContainsAlias(string alias)
{
return _aliases.Contains(alias);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ namespace Musoq.Evaluator.Utils.Symbols;

public class IndexBasedContextsPositionsSymbol : Symbol
{
private readonly IDictionary<int, (string[] Left, string[] Right)> _contextsPositions = new Dictionary<int, (string[] Left, string[] Right)>();
private readonly Dictionary<int, (string[] Left, string[] Right)> _contextsPositions = new();

public int GetIndexFor(int index, string alias)
{
var leftRight = _contextsPositions[index];

var inLeftIndex = Array.IndexOf(leftRight.Left, alias);

return inLeftIndex != -1 ? inLeftIndex : Array.IndexOf(leftRight.Right, alias);
return inLeftIndex == -1 ? Array.IndexOf(leftRight.Right, alias) : inLeftIndex;
}

public void Add(IReadOnlyCollection<string> lines)
Expand Down
Loading
Loading