Skip to content

TrinoFunction - new unit tests and some fixes for bugs using certain parameter types #24

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
112 changes: 112 additions & 0 deletions trino-csharp/Trino.Client.Test/TrinoFunctionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using Trino.Client.Utils;

namespace Trino.Client.Test
{
[TestClass]
public class TrinoFunctionTests
{
/// <summary>
/// We subclass the TrinoFunction class to easily access the output from BuildFunctionStatement()
/// </summary>
class TrinoFunctionTestHelper : TrinoFunction
{
public TrinoFunctionTestHelper(string catalog, string functionName, IList<object> parameters) : base(catalog, functionName, parameters)
{
}

public string GetStatement()
{
return base.BuildFunctionStatement();
}
}

[TestMethod]
public void TestNoParams()
{
var testTrinoFunction = new TrinoFunctionTestHelper("test", "testFunc", []);
var statement = testTrinoFunction.GetStatement();

Assert.AreEqual("test.testFunc()", statement);
}

[TestMethod]
public void TestOneStringParam()
{
var testTrinoFunction = new TrinoFunctionTestHelper("test", "testFunc", ["a"]);
var statement = testTrinoFunction.GetStatement();

Assert.AreEqual("test.testFunc('a')", statement);
}

[TestMethod]
public void TestTwoStringParams()
{
var testTrinoFunction = new TrinoFunctionTestHelper("test", "testFunc", ["a", "b"]);
var statement = testTrinoFunction.GetStatement();

Assert.AreEqual("test.testFunc('a', 'b')", statement);
}

[TestMethod]
public void TestNullCatalogue()
{
var testTrinoFunction = new TrinoFunctionTestHelper(null!, "testFunc", []);
var statement = testTrinoFunction.GetStatement();

Assert.AreEqual("testFunc()", statement);
}

[TestMethod]
public void TestEmptyCatalogue()
{
var testTrinoFunction = new TrinoFunctionTestHelper(string.Empty, "testFunc", []);
var statement = testTrinoFunction.GetStatement();

Assert.AreEqual("testFunc()", statement);
}

[TestMethod]
public void TestIntegralParams()
{
IList<object> args = [(sbyte)1, (byte)2, (short)3, (ushort)4, 5, 6U, 7L, 8UL, (nint)9, (nuint)10];
var testTrinoFunction = new TrinoFunctionTestHelper(string.Empty, "testFunc", args);
var statement = testTrinoFunction.GetStatement();

Assert.AreEqual("testFunc(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)", statement);
}

[TestMethod]
public void TestFractionalParams()
{
IList<object> args = [1.5f, 2.5d, 3.5m];
var testTrinoFunction = new TrinoFunctionTestHelper(string.Empty, "testFunc", args);
var statement = testTrinoFunction.GetStatement();

Assert.AreEqual("testFunc(1.5, 2.5, 3.5)", statement);
}

[TestMethod]
public void TestBooleanParams()
{
IList<object> args = [true, false];
var testTrinoFunction = new TrinoFunctionTestHelper(string.Empty, "testFunc", args);
var statement = testTrinoFunction.GetStatement();

Assert.AreEqual("testFunc(1, 0)", statement);
}

[TestMethod]
public void TestDateParams()
{
IList<object> args = [
new DateTime(2025, 4, 3),
new DateTime(2025, 4, 3, 12, 0, 0),
new DateTimeOffset(2025, 4, 3, 12, 0, 0, new TimeSpan(1, 0, 0))
];
var testTrinoFunction = new TrinoFunctionTestHelper(string.Empty, "testFunc", args);
var statement = testTrinoFunction.GetStatement();

Assert.AreEqual("testFunc('2025-04-03T00:00:00', '2025-04-03T12:00:00', '2025-04-03T12:00:00')", statement);
}
}
}
62 changes: 44 additions & 18 deletions trino-csharp/Trino.Client/Utils/TrinoFunction.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace Trino.Client.Utils
Expand All @@ -25,37 +25,63 @@ public virtual Task<RecordExecutor> ExecuteAsync(ClientSession session)

protected virtual string BuildFunctionStatement()
{
StringBuilder stringBuilder = new StringBuilder();
var fullFunctionName = BuildFullFunctionName();
var parameterString = string.Join(", ", FormatParameters());

return $"{fullFunctionName}({parameterString})";
}

private string BuildFullFunctionName()
{
if (!string.IsNullOrEmpty(catalog))
{
stringBuilder.Append(this.catalog);
stringBuilder.Append(".");
return $"{catalog}.{functionName}";
}
stringBuilder.Append(this.functionName);
stringBuilder.Append("(");

for (int i = 0; i < Parameters.Count; i++)
return functionName;
}

private IEnumerable<string> FormatParameters()
{
foreach (var parameter in Parameters)
{
if (i > 0)
if (IsNumeric(parameter))
{
stringBuilder.Append(", ");
yield return parameter.ToString();
}

// if parameter is a digit, do not quote it
if (Parameters[i] is int || Parameters[i] is long || Parameters[i] is float || Parameters[i] is double)
else if (parameter is bool)
{
stringBuilder.Append(Parameters[i]);
yield return (bool)parameter ? "1" : "0";
}
else if (parameter is DateTime)
{
yield return QuoteParameter(((DateTime)parameter).ToString("s"));
}
else if (parameter is DateTimeOffset)
{
yield return QuoteParameter(((DateTimeOffset)parameter).ToString("s"));
}
else
{
stringBuilder.Append("'");
stringBuilder.Append(Parameters[i]);
stringBuilder.Append("'");
yield return QuoteParameter(parameter.ToString());
}
}
stringBuilder.Append(")");
}

return stringBuilder.ToString();
private static bool IsNumeric(object parameter)
{
return parameter is byte || parameter is sbyte
|| parameter is short || parameter is ushort
|| parameter is int || parameter is uint
|| parameter is long || parameter is ulong
|| parameter is IntPtr || parameter is UIntPtr
|| parameter is float || parameter is double
|| parameter is decimal;
}

private static string QuoteParameter(string formattedParameter)
{
return $"'{formattedParameter}'";
}
}
}