minor fix an issue in label/type inference (#9)
This commit is contained in:
Родитель
4a661c7358
Коммит
d27ce77742
|
@ -14,7 +14,6 @@ using System.Text.RegularExpressions;
|
|||
using openCypherTranspiler.Common.Exceptions;
|
||||
using openCypherTranspiler.Common.Logging;
|
||||
using openCypherTranspiler.openCypherParser.ANTLR;
|
||||
using openCypherTranspiler.openCypherParser.AST;
|
||||
using openCypherTranspiler.openCypherParser.Common;
|
||||
using openCypherTranspiler.Common.Utils;
|
||||
|
||||
|
@ -387,22 +386,16 @@ namespace openCypherTranspiler.openCypherParser.AST
|
|||
Enumerable.Empty<string>();
|
||||
|
||||
var returnedExprs = allReturnedEntities
|
||||
.Select(g =>
|
||||
{
|
||||
if (g.Select(e => e.EntityName).Where(en => !string.IsNullOrEmpty(en)).Distinct().Count() > 1)
|
||||
{
|
||||
throw new TranspilerSyntaxErrorException($"Multiple labels assigned to same alias {g.Key}: {string.Join(",", g.Select(e => e.EntityName).Where(en => !string.IsNullOrEmpty(en)))}");
|
||||
}
|
||||
return new QueryExpressionWithAlias()
|
||||
.Select(g => new QueryExpressionWithAlias()
|
||||
{
|
||||
Alias = g.Key,
|
||||
InnerExpression = new QueryExpressionProperty()
|
||||
{
|
||||
Entity = g.FirstOrDefault(en => !string.IsNullOrEmpty(en.EntityName)).Clone(),
|
||||
Entity = g.First().Clone(),
|
||||
VariableName = g.Key
|
||||
}
|
||||
};
|
||||
})
|
||||
}
|
||||
)
|
||||
.Union(
|
||||
allInheritedProperties.Select(alias =>
|
||||
new QueryExpressionWithAlias()
|
||||
|
@ -656,7 +649,7 @@ namespace openCypherTranspiler.openCypherParser.AST
|
|||
// In finalizing the SingleQueryNode, we ensure on a best-effort basis that all entity references
|
||||
// have its type spelled out, e.g. In
|
||||
// MATCH (a:Person), (a) WITH a ...
|
||||
// the subsequence reference to 'a' will be marked as entity type 'Person'
|
||||
// the subsequence reference to 'a' will have same implied node type 'Person'
|
||||
//
|
||||
// To do this, we walk up the tree (bear in mind: bottom of the tree is earlier in the openCypher
|
||||
// query, and root node of the tree is the final result) and in each layer
|
||||
|
@ -688,8 +681,11 @@ namespace openCypherTranspiler.openCypherParser.AST
|
|||
// first pass, propagate all node and edge labels for those sharing aliases
|
||||
entitiesInReturn
|
||||
.Values
|
||||
.Union(inheritedEntities)
|
||||
.Union(entitiesInMatchPatterns)
|
||||
.Where(e => !string.IsNullOrEmpty(e.Alias)) // skip over all anonymous node/edge. we later assert that they all have types already specified explicitly
|
||||
// skip over anonymous node/edge and untyped entities aliases: they should have type
|
||||
// already supplied explicitly (which we ensure during parsing, e.g. we don't allow [] or () for now)
|
||||
.Where(e => !string.IsNullOrEmpty(e.Alias))
|
||||
.GroupBy(e => e.Alias)
|
||||
.ToList()
|
||||
.ForEach(g =>
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace openCypherTranspiler.openCypherParser.AST
|
|||
public IList<MatchPattern> MatchPatterns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Return a new MatchDataSource mirrors the old one but with anonymous entities filled with
|
||||
/// Return a new MatchClause mirrors the old one but with anonymous entities filled with
|
||||
/// a place holder alias
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
|
@ -60,8 +60,7 @@ namespace openCypherTranspiler.openCypherParser.AST
|
|||
throw new TranspilerSyntaxErrorException($"Banned prefix for variable aliases: {anonVarPrefix}. Please consider a different prefix.");
|
||||
}
|
||||
|
||||
// creating a new DS with implied labels fixed up
|
||||
var matchDsNew = new MatchClause()
|
||||
return new MatchClause()
|
||||
{
|
||||
MatchPatterns = MatchPatterns.Select(p => new MatchPattern(p.IsOptionalMatch, p.Select(e =>
|
||||
{
|
||||
|
@ -71,8 +70,6 @@ namespace openCypherTranspiler.openCypherParser.AST
|
|||
return entity;
|
||||
}))).ToList()
|
||||
};
|
||||
|
||||
return matchDsNew;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -191,6 +191,50 @@ RETURN toUpper(p.Name) as NameCapital, toLower(m.Title) as TitleLC
|
|||
Assert.IsTrue(tree.GetChildrenOfType<QueryExpressionFunction>().Any(expr => expr.Function.FunctionName == Function.StringToLower));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LabelTypeInferenceTest()
|
||||
{
|
||||
// Positive case already covered in many other tests
|
||||
// Today we only support node label type to be specified
|
||||
// implicitly when its aliases appeared more than once
|
||||
|
||||
// Negative case when the label cannot be inferred
|
||||
{
|
||||
var expectedExceptionThrown = false;
|
||||
try
|
||||
{
|
||||
var tree = RunQueryAndDumpTree(@"
|
||||
MATCH (p)-[:ACTED_IN]-(m:Movie)
|
||||
RETURN p.Name AS Name, m.Title as Title
|
||||
"
|
||||
);
|
||||
}
|
||||
catch (TranspilerSyntaxErrorException)
|
||||
{
|
||||
expectedExceptionThrown = true;
|
||||
}
|
||||
Assert.IsTrue(expectedExceptionThrown);
|
||||
}
|
||||
|
||||
// Negative case when the type cannot be inferred
|
||||
{
|
||||
var expectedExceptionThrown = false;
|
||||
try
|
||||
{
|
||||
var tree = RunQueryAndDumpTree(@"
|
||||
MATCH (p:Person)-[somewhatlinkedto]-(m:Movie)
|
||||
RETURN p.Name AS Name, m.Title as Title
|
||||
"
|
||||
);
|
||||
}
|
||||
catch (TranspilerSyntaxErrorException)
|
||||
{
|
||||
expectedExceptionThrown = true;
|
||||
}
|
||||
Assert.IsTrue(expectedExceptionThrown);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OtherWeirdSyntaxTest()
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче