From 62997f87c3016213a77ec713d25d3440767f360b Mon Sep 17 00:00:00 2001 From: Neil MacMullen Date: Sat, 18 Jan 2025 13:09:29 +0000 Subject: [PATCH] Add isFinite etc Fix issue where kql comment treated as break --- .../BuiltIns/BuiltInScalarFunctions.cs | 7 ++ .../BuiltIns/Operators/DivideFunction.cs | 4 +- .../ScalarFunctions/IsAsciiFunction.cs | 28 +++++++ .../ScalarFunctions/IsEmptyFunction.cs | 5 +- .../ScalarFunctions/IsFiniteFunction.cs | 8 ++ .../BuiltIns/ScalarFunctions/IsInfFunction.cs | 17 +++++ .../ScalarFunctions/IsNotEmptyFunction.cs | 8 ++ .../lokql-engine/InteractiveTableExplorer.cs | 2 +- libraries/lokql-engine/lokql-engine.csproj | 2 +- test/BasicTests/SimpleFunctionTests.cs | 74 +++++++++++++++++++ 10 files changed, 149 insertions(+), 6 deletions(-) create mode 100644 libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsAsciiFunction.cs create mode 100644 libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsFiniteFunction.cs create mode 100644 libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsInfFunction.cs create mode 100644 libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsNotEmptyFunction.cs diff --git a/libraries/KustoLoco.Core/Evaluation/BuiltIns/BuiltInScalarFunctions.cs b/libraries/KustoLoco.Core/Evaluation/BuiltIns/BuiltInScalarFunctions.cs index ebf558ca..86313961 100644 --- a/libraries/KustoLoco.Core/Evaluation/BuiltIns/BuiltInScalarFunctions.cs +++ b/libraries/KustoLoco.Core/Evaluation/BuiltIns/BuiltInScalarFunctions.cs @@ -36,6 +36,13 @@ static BuiltInScalarFunctions() IsEmptyFunction.Register(functions); + IsNotEmptyFunction.Register(functions); + IsAsciiFunction.Register(functions); + IsFiniteFunction.Register(functions); + IsInfFunction.Register(functions); + IsNanFunction.Register(functions); + IsUtf8Function.Register(functions); + ReverseFunction.Register(functions); functions.Add( Functions.MinOf, new ScalarFunctionInfo( diff --git a/libraries/KustoLoco.Core/Evaluation/BuiltIns/Operators/DivideFunction.cs b/libraries/KustoLoco.Core/Evaluation/BuiltIns/Operators/DivideFunction.cs index 6862ae28..f820da57 100644 --- a/libraries/KustoLoco.Core/Evaluation/BuiltIns/Operators/DivideFunction.cs +++ b/libraries/KustoLoco.Core/Evaluation/BuiltIns/Operators/DivideFunction.cs @@ -17,9 +17,7 @@ internal partial class DivideFunction : a / b; private static double? DoubleImpl(double a, double b) - => b == 0 - ? null - : a / b; + => a / b; private static TimeSpan? TsLongImpl(TimeSpan a, long b) => b == 0 diff --git a/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsAsciiFunction.cs b/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsAsciiFunction.cs new file mode 100644 index 00000000..bebdfdd5 --- /dev/null +++ b/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsAsciiFunction.cs @@ -0,0 +1,28 @@ +using System.Linq; +using System.Text; +using System.Text.Unicode; + +namespace KustoLoco.Core.Evaluation.BuiltIns.Impl; +// ReSharper disable PartialTypeWithSinglePart +[KustoImplementation(Keyword = "Functions.IsAscii")] +internal partial class IsAsciiFunction +{ + internal static bool Impl(string s) => Ascii.IsValid(s); +} + + +// ReSharper disable PartialTypeWithSinglePart +[KustoImplementation(Keyword = "Functions.Reverse")] +internal partial class ReverseFunction +{ + internal static string Impl(string s) => new string(s.Reverse().ToArray()); +} + +[KustoImplementation(Keyword = "Functions.IsUtf8")] +internal partial class IsUtf8Function +{ + //it'a a little unclear how this could ever return false. + //In theory we can have some bytes that are not valid utf8, + //but how would the get turned into a string in the tables? + internal static bool Impl(string s) => true; +} diff --git a/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsEmptyFunction.cs b/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsEmptyFunction.cs index 90a9c7ab..d1373c4d 100644 --- a/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsEmptyFunction.cs +++ b/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsEmptyFunction.cs @@ -5,4 +5,7 @@ internal partial class IsEmptyFunction { internal static bool Impl(string s) => s.Length == 0; -} \ No newline at end of file +} + + +// ReSharper disable PartialTypeWithSinglePart diff --git a/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsFiniteFunction.cs b/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsFiniteFunction.cs new file mode 100644 index 00000000..21ea6a35 --- /dev/null +++ b/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsFiniteFunction.cs @@ -0,0 +1,8 @@ +namespace KustoLoco.Core.Evaluation.BuiltIns.Impl; + +[KustoImplementation(Keyword = "Functions.IsFinite")] +internal partial class IsFiniteFunction +{ + internal static bool Impl(double v) => + double.IsFinite(v); +} diff --git a/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsInfFunction.cs b/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsInfFunction.cs new file mode 100644 index 00000000..90c5f995 --- /dev/null +++ b/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsInfFunction.cs @@ -0,0 +1,17 @@ +namespace KustoLoco.Core.Evaluation.BuiltIns.Impl; + +[KustoImplementation(Keyword = "Functions.IsInf")] +internal partial class IsInfFunction +{ + internal static bool Impl(double v) => + double.IsInfinity(v); +} + +[KustoImplementation(Keyword = "Functions.IsNan")] +internal partial class IsNanFunction +{ + internal static bool Impl(double v) => + double.IsNaN(v); +} + + diff --git a/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsNotEmptyFunction.cs b/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsNotEmptyFunction.cs new file mode 100644 index 00000000..01c41881 --- /dev/null +++ b/libraries/KustoLoco.Core/Evaluation/BuiltIns/ScalarFunctions/IsNotEmptyFunction.cs @@ -0,0 +1,8 @@ +namespace KustoLoco.Core.Evaluation.BuiltIns.Impl; + +// ReSharper disable PartialTypeWithSinglePart +[KustoImplementation(Keyword = "Functions.IsNotEmpty")] +internal partial class IsNotEmptyFunction +{ + internal static bool Impl(string s) => s is { Length: > 0 }; +} diff --git a/libraries/lokql-engine/InteractiveTableExplorer.cs b/libraries/lokql-engine/InteractiveTableExplorer.cs index 51380254..291a5543 100644 --- a/libraries/lokql-engine/InteractiveTableExplorer.cs +++ b/libraries/lokql-engine/InteractiveTableExplorer.cs @@ -132,7 +132,7 @@ public async Task RunNextBlock(BlockSequence blocks) .Trim(); //support comments - if (query.StartsWith("#") || query.StartsWith("//") || query.IsBlank()) return; + if (query.StartsWith("#") || query.IsBlank()) return; try { diff --git a/libraries/lokql-engine/lokql-engine.csproj b/libraries/lokql-engine/lokql-engine.csproj index ed81db61..77819cc0 100644 --- a/libraries/lokql-engine/lokql-engine.csproj +++ b/libraries/lokql-engine/lokql-engine.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 Lokql.Engine enable enable diff --git a/test/BasicTests/SimpleFunctionTests.cs b/test/BasicTests/SimpleFunctionTests.cs index 2a8271df..c9409281 100644 --- a/test/BasicTests/SimpleFunctionTests.cs +++ b/test/BasicTests/SimpleFunctionTests.cs @@ -670,4 +670,78 @@ public async Task MultiStringCat() result.Should().Be("123456789012345"); } + [TestMethod] + public async Task IsEmpty() + { + var query = "print isempty('')"; + var result = await LastLineOfResult(query); + result.Should().Be("True"); + } + + [TestMethod] + public async Task IsEmpty2() + { + var query = "print isempty(' ')"; + var result = await LastLineOfResult(query); + result.Should().Be("False"); + } + + [TestMethod] + public async Task IsNotEmpty() + { + var query = "print isnotempty('')"; + var result = await LastLineOfResult(query); + result.Should().Be("False"); + } + + [TestMethod] + public async Task IsNotEmpty2() + { + var query = "print isnotempty(' ')"; + var result = await LastLineOfResult(query); + result.Should().Be("True"); + } + + + [TestMethod] + public async Task IsAscii() + { + var query = "print isascii('blahhh')"; + var result = await LastLineOfResult(query); + result.Should().Be("True"); + } + + [TestMethod] + public async Task IsUtf8() + { + var query = "print isutf8('blahhh')"; + var result = await LastLineOfResult(query); + result.Should().Be("True"); + } + + [TestMethod] + public async Task Reverse() + { + var query = "print reverse('acdef')"; + var result = await LastLineOfResult(query); + result.Should().Be("fedca"); + } + + [TestMethod] + public async Task IsFinite() + { + var query = "print isfinite(1.0/10)"; + var result = await LastLineOfResult(query); + result.Should().Be("True"); + } + + //[Ignore("TODO - isFinite needs work")] + [TestMethod] + public async Task IsFinite2() + { + var query = "print isfinite(1.0/0.0)"; + var result = await LastLineOfResult(query); + result.Should().Be("False"); + } + }