diff --git a/examples/simple/simple.csproj b/examples/simple/simple.csproj
index 134e583..e2a4b1e 100644
--- a/examples/simple/simple.csproj
+++ b/examples/simple/simple.csproj
@@ -10,10 +10,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/Common/Common.csproj b/src/Common/Common.csproj
index e50775f..3dbb10a 100644
--- a/src/Common/Common.csproj
+++ b/src/Common/Common.csproj
@@ -18,7 +18,7 @@
openCypher transpiler graph C# .NET
git
https://github.com/microsoft/openCypherTranspiler/tree/master/src/openCypherParser
- 0.1.0
+ 0.1.1
diff --git a/src/Common/Utils/TypeHelper.cs b/src/Common/Utils/TypeHelper.cs
index 856e0f0..5671523 100644
--- a/src/Common/Utils/TypeHelper.cs
+++ b/src/Common/Utils/TypeHelper.cs
@@ -14,7 +14,7 @@ namespace openCypherTranspiler.Common.Utils
///
/// Check if null value can be assigned
/// E.g. IsNullableType(string) = true, IsNullableType(DateTime) = false
- /// IsNullableType(
+ /// IsNullableType(System.Nullable) = true
///
///
///
diff --git a/src/LogicalPlanner/LogicalPlanner.csproj b/src/LogicalPlanner/LogicalPlanner.csproj
index 3f567f5..df4b874 100644
--- a/src/LogicalPlanner/LogicalPlanner.csproj
+++ b/src/LogicalPlanner/LogicalPlanner.csproj
@@ -18,7 +18,7 @@
openCypher transpiler graph C# .NET
git
https://github.com/microsoft/openCypherTranspiler/tree/master/src/LogicalPlanner
- 0.1.0
+ 0.1.1
diff --git a/src/SQLRenderer/SQLRenderer.csproj b/src/SQLRenderer/SQLRenderer.csproj
index a8e5c90..9df88cb 100644
--- a/src/SQLRenderer/SQLRenderer.csproj
+++ b/src/SQLRenderer/SQLRenderer.csproj
@@ -18,7 +18,7 @@
openCypher transpiler graph C# .NET
git
https://github.com/microsoft/openCypherTranspiler/tree/master/src/openCypherParser
- 0.1.0
+ 0.1.1
diff --git a/src/openCypherParser/AST/Expressions/QueryExpressionFunction.cs b/src/openCypherParser/AST/Expressions/QueryExpressionFunction.cs
index 64f6403..86ce020 100644
--- a/src/openCypherParser/AST/Expressions/QueryExpressionFunction.cs
+++ b/src/openCypherParser/AST/Expressions/QueryExpressionFunction.cs
@@ -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:
diff --git a/src/openCypherParser/Common/Function.cs b/src/openCypherParser/Common/Function.cs
index e2558c5..c87c136 100644
--- a/src/openCypherParser/Common/Function.cs
+++ b/src/openCypherParser/Common/Function.cs
@@ -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());
+ }
}
},
};
diff --git a/src/openCypherParser/openCypherParser.csproj b/src/openCypherParser/openCypherParser.csproj
index a51d3ab..93d81d8 100644
--- a/src/openCypherParser/openCypherParser.csproj
+++ b/src/openCypherParser/openCypherParser.csproj
@@ -18,7 +18,7 @@
openCypher transpiler graph C# .NET
git
https://github.com/microsoft/openCypherTranspiler/tree/master/src/openCypherParser
- 0.1.0
+ 0.1.1
CS3021
diff --git a/tests/LogicalPlanner.Test/LogicalPlannerTest.cs b/tests/LogicalPlanner.Test/LogicalPlannerTest.cs
index 155169b..b97164f 100644
--- a/tests/LogicalPlanner.Test/LogicalPlannerTest.cs
+++ b/tests/LogicalPlanner.Test/LogicalPlannerTest.cs
@@ -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()
{