better param checks for built-in value functions (#8)

This commit is contained in:
Jerry Liang 2019-10-22 14:33:16 -07:00 коммит произвёл GitHub
Родитель bc9fcc694d
Коммит 4a661c7358
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 110 добавлений и 27 удалений

Просмотреть файл

@ -10,10 +10,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="openCypherTranspiler.Common" Version="0.1.0" />
<PackageReference Include="openCypherTranspiler.openCypherParser" Version="0.1.0" />
<PackageReference Include="openCypherTranspiler.LogicalPlanner" Version="0.1.0" />
<PackageReference Include="openCypherTranspiler.SQLRenderer" Version="0.1.0" />
<PackageReference Include="openCypherTranspiler.Common" Version="0.1.1" />
<PackageReference Include="openCypherTranspiler.openCypherParser" Version="0.1.1" />
<PackageReference Include="openCypherTranspiler.LogicalPlanner" Version="0.1.1" />
<PackageReference Include="openCypherTranspiler.SQLRenderer" Version="0.1.1" />
</ItemGroup>
</Project>

Просмотреть файл

@ -18,7 +18,7 @@
<PackageTags>openCypher transpiler graph C# .NET</PackageTags>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/microsoft/openCypherTranspiler/tree/master/src/openCypherParser</RepositoryUrl>
<VersionPrefix>0.1.0</VersionPrefix>
<VersionPrefix>0.1.1</VersionPrefix>
</PropertyGroup>
<ItemGroup>

Просмотреть файл

@ -14,7 +14,7 @@ namespace openCypherTranspiler.Common.Utils
/// <summary>
/// Check if null value can be assigned
/// E.g. IsNullableType(string) = true, IsNullableType(DateTime) = false
/// IsNullableType(
/// IsNullableType(System.Nullable<int>) = true
/// </summary>
/// <param name="type"></param>
/// <returns></returns>

Просмотреть файл

@ -18,7 +18,7 @@
<PackageTags>openCypher transpiler graph C# .NET</PackageTags>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/microsoft/openCypherTranspiler/tree/master/src/LogicalPlanner</RepositoryUrl>
<VersionPrefix>0.1.0</VersionPrefix>
<VersionPrefix>0.1.1</VersionPrefix>
</PropertyGroup>
<ItemGroup>

Просмотреть файл

@ -18,7 +18,7 @@
<PackageTags>openCypher transpiler graph C# .NET</PackageTags>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/microsoft/openCypherTranspiler/tree/master/src/openCypherParser</RepositoryUrl>
<VersionPrefix>0.1.0</VersionPrefix>
<VersionPrefix>0.1.1</VersionPrefix>
</PropertyGroup>
<ItemGroup>

Просмотреть файл

@ -39,23 +39,23 @@ namespace openCypherTranspiler.openCypherParser.AST
public override Type EvaluateType()
{
var innerType = InnerExpression.EvaluateType();
var isWrappedinNullable = TypeHelper.IsSystemNullableType(innerType);
var canBeNull = TypeHelper.CanAssignNullToType(innerType);
switch (Function.FunctionName)
{
case Common.Function.ToFloat:
return isWrappedinNullable ? typeof(float?) : typeof(float);
return canBeNull ? typeof(float?) : typeof(float);
case Common.Function.ToString:
return typeof(string);
case Common.Function.ToBoolean:
return isWrappedinNullable ? typeof(bool?) : typeof(bool);
return canBeNull ? typeof(bool?) : typeof(bool);
case Common.Function.ToInteger:
return isWrappedinNullable ? typeof(int?) : typeof(int);
return canBeNull ? typeof(int?) : typeof(int);
case Common.Function.ToDouble:
return isWrappedinNullable ? typeof(long?) : typeof(long);
return canBeNull ? typeof(long?) : typeof(long);
case Common.Function.ToLong:
return isWrappedinNullable ? typeof(double?) : typeof(double);
return canBeNull ? typeof(double?) : typeof(double);
case Common.Function.Not:
return isWrappedinNullable ? typeof(bool?) : typeof(bool);
return canBeNull ? typeof(bool?) : typeof(bool);
case Common.Function.StringContains:
case Common.Function.StringStartsWith:
case Common.Function.StringEndsWith:

Просмотреть файл

@ -82,6 +82,26 @@ namespace openCypherTranspiler.openCypherParser.Common
}
}
private static void EnsureStringType(FunctionInfo info, Type type)
{
if (!(
type == typeof(string)
))
{
throw new TranspilerNotSupportedException($"Function {info.FunctionName} parameter of type {type.Name}");
}
}
private static void EnsureLengthType(FunctionInfo info, Type type)
{
if (!(
type == typeof(int) || type == typeof(long)
))
{
throw new TranspilerNotSupportedException($"Function {info.FunctionName} parameter of type {type.Name}");
}
}
private static void EnsureBooleanType(FunctionInfo info, Type type)
{
if (!(
@ -188,7 +208,11 @@ namespace openCypherTranspiler.openCypherParser.Common
FunctionName = Function.StringStartsWith,
RequiredParameters = 2,
OptionalParameters = 0,
ParameterChecker = EnsureParameterCountChecker
ParameterChecker = (info, types) => {
EnsureParameterCount(info, types.Count());
EnsureStringType(info, types.First());
EnsureStringType(info, types.Skip(1).First());
}
}
},
{ "stringendswith", new FunctionInfo()
@ -196,7 +220,11 @@ namespace openCypherTranspiler.openCypherParser.Common
FunctionName = Function.StringEndsWith,
RequiredParameters = 2,
OptionalParameters = 0,
ParameterChecker = EnsureParameterCountChecker
ParameterChecker = (info, types) => {
EnsureParameterCount(info, types.Count());
EnsureStringType(info, types.First());
EnsureStringType(info, types.Skip(1).First());
}
}
},
{ "stringcontains", new FunctionInfo()
@ -204,7 +232,11 @@ namespace openCypherTranspiler.openCypherParser.Common
FunctionName = Function.StringContains,
RequiredParameters = 2,
OptionalParameters = 0,
ParameterChecker = EnsureParameterCountChecker
ParameterChecker = (info, types) => {
EnsureParameterCount(info, types.Count());
EnsureStringType(info, types.First());
EnsureStringType(info, types.Skip(1).First());
}
}
},
{ "isnull", new FunctionInfo()
@ -228,7 +260,11 @@ namespace openCypherTranspiler.openCypherParser.Common
FunctionName = Function.StringLeft,
RequiredParameters = 2,
OptionalParameters = 0,
ParameterChecker = EnsureParameterCountChecker
ParameterChecker = (info, types) => {
EnsureParameterCount(info, types.Count());
EnsureStringType(info, types.First());
EnsureLengthType(info, types.Skip(1).First());
}
}
},
{ "right", new FunctionInfo()
@ -236,7 +272,11 @@ namespace openCypherTranspiler.openCypherParser.Common
FunctionName = Function.StringRight,
RequiredParameters = 2,
OptionalParameters = 0,
ParameterChecker = EnsureParameterCountChecker
ParameterChecker = (info, types) => {
EnsureParameterCount(info, types.Count());
EnsureStringType(info, types.First());
EnsureLengthType(info, types.Skip(1).First());
}
}
},
{ "trim", new FunctionInfo()
@ -244,7 +284,10 @@ namespace openCypherTranspiler.openCypherParser.Common
FunctionName = Function.StringTrim,
RequiredParameters = 1,
OptionalParameters = 0,
ParameterChecker = EnsureParameterCountChecker
ParameterChecker = (info, types) => {
EnsureParameterCount(info, types.Count());
EnsureStringType(info, types.First());
}
}
},
{ "ltrim", new FunctionInfo()
@ -252,7 +295,10 @@ namespace openCypherTranspiler.openCypherParser.Common
FunctionName = Function.StringLTrim,
RequiredParameters = 1,
OptionalParameters = 0,
ParameterChecker = EnsureParameterCountChecker
ParameterChecker = (info, types) => {
EnsureParameterCount(info, types.Count());
EnsureStringType(info, types.First());
}
}
},
{ "rtrim", new FunctionInfo()
@ -260,7 +306,10 @@ namespace openCypherTranspiler.openCypherParser.Common
FunctionName = Function.StringRTrim,
RequiredParameters = 1,
OptionalParameters = 0,
ParameterChecker = EnsureParameterCountChecker
ParameterChecker = (info, types) => {
EnsureParameterCount(info, types.Count());
EnsureStringType(info, types.First());
}
}
},
{ "toupper", new FunctionInfo()
@ -268,7 +317,10 @@ namespace openCypherTranspiler.openCypherParser.Common
FunctionName = Function.StringToUpper,
RequiredParameters = 1,
OptionalParameters = 0,
ParameterChecker = EnsureParameterCountChecker
ParameterChecker = (info, types) => {
EnsureParameterCount(info, types.Count());
EnsureStringType(info, types.First());
}
}
},
{ "tolower", new FunctionInfo()
@ -276,7 +328,10 @@ namespace openCypherTranspiler.openCypherParser.Common
FunctionName = Function.StringToLower,
RequiredParameters = 1,
OptionalParameters = 0,
ParameterChecker = EnsureParameterCountChecker
ParameterChecker = (info, types) => {
EnsureParameterCount(info, types.Count());
EnsureStringType(info, types.First());
}
}
},
{ "size", new FunctionInfo()
@ -284,7 +339,10 @@ namespace openCypherTranspiler.openCypherParser.Common
FunctionName = Function.StringSize,
RequiredParameters = 1,
OptionalParameters = 0,
ParameterChecker = EnsureParameterCountChecker
ParameterChecker = (info, types) => {
EnsureParameterCount(info, types.Count());
EnsureStringType(info, types.First());
}
}
},
};

Просмотреть файл

@ -18,7 +18,7 @@
<PackageTags>openCypher transpiler graph C# .NET</PackageTags>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/microsoft/openCypherTranspiler/tree/master/src/openCypherParser</RepositoryUrl>
<VersionPrefix>0.1.0</VersionPrefix>
<VersionPrefix>0.1.1</VersionPrefix>
<NoWarn>CS3021</NoWarn>
</PropertyGroup>

Просмотреть файл

@ -13,6 +13,7 @@ using openCypherTranspiler.openCypherParser;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using JT = openCypherTranspiler.LogicalPlanner.JoinOperator.JoinType;
using System;
namespace openCypherTranspiler.LogicalPlanner.Test
{
@ -352,6 +353,30 @@ ORDER BY p.Name LIMIT 3
}
}
[TestMethod]
public void TypeEvaluationTest()
{
IGraphSchemaProvider graphDef = new JSONGraphSchema(@"./TestData/MovieGraph.json");
// Basic test covers type coercion and type evaluation
{
var lp = RunQueryAndDumpTree(graphDef, @"
MATCH (p:Person)-[a:ACTED_IN]->(m:Movie)
WITH toString(m.Released) as ReleasedStr, m.Released as ReleasedInt
RETURN toInteger(ReleasedStr) as Released, toFloat(ReleasedStr) as ReleasedFloat, toFloat(ReleasedStr)/10.0 as ReleasedDouble, toBoolean(""true"") as ReleasedBool, toFloat(ReleasedStr)+ReleasedInt as ReleasedFloat2
"
);
Assert.IsTrue(lp.StartingOperators.Count() > 0);
Assert.IsTrue(lp.TerminalOperators.Count() == 1);
Assert.IsTrue(lp.TerminalOperators.First().OutputSchema.Count == 5);
Assert.IsTrue(lp.TerminalOperators.First().OutputSchema.Any(o => o.FieldAlias == "Released" && ((o as ValueField)?.FieldType ?? default(Type)) == typeof(int?)));
Assert.IsTrue(lp.TerminalOperators.First().OutputSchema.Any(o => o.FieldAlias == "ReleasedFloat" && ((o as ValueField)?.FieldType ?? default(Type)) == typeof(float?)));
Assert.IsTrue(lp.TerminalOperators.First().OutputSchema.Any(o => o.FieldAlias == "ReleasedDouble" && ((o as ValueField)?.FieldType ?? default(Type)) == typeof(double?)));
Assert.IsTrue(lp.TerminalOperators.First().OutputSchema.Any(o => o.FieldAlias == "ReleasedBool" && ((o as ValueField)?.FieldType ?? default(Type)) == typeof(bool?)));
Assert.IsTrue(lp.TerminalOperators.First().OutputSchema.Any(o => o.FieldAlias == "ReleasedFloat2" && ((o as ValueField)?.FieldType ?? default(Type)) == typeof(float?)));
}
}
[TestMethod]
public void AdvancedTestLogicalPlanner()
{