Skip to content
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

Support Guid ToString in SqLite, add test for mssql and sqlite #4297

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
1 change: 0 additions & 1 deletion Source/LinqToDB/Linq/Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,6 @@ public void SetInfo(MappingSchema mappingSchema)
{ MT<uint? >(() => ((uint?) 0) .ToString()!), N(() => L<uint?, string>((uint? p0) => p0!.Value.ToString() )) },
{ MT<ulong? >(() => ((ulong?) 0) .ToString()!), N(() => L<ulong?, string>((ulong? p0) => p0!.Value.ToString() )) },

jogibear9988 marked this conversation as resolved.
Show resolved Hide resolved

// handle all other as default
#pragma warning disable MA0107 // object.ToString is bad, m'kay?
{ MT<object>(() => ((object)0).ToString()!), N(() => L<object, string>((object p0) => Sql.ConvertTo<string>.From(p0) )) },
Expand Down
41 changes: 39 additions & 2 deletions Source/LinqToDB/Sql/Sql.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq.Expressions;
using System.Reflection;

using JetBrains.Annotations;

using PN = LinqToDB.ProviderName;

// ReSharper disable CheckNamespace
// ReSharper disable RedundantNameQualifier

namespace LinqToDB
{
using Mapping;
using Common;
using Expressions;
using Linq;
using Mapping;
using SqlQuery;
using LinqToDB.Common;

[PublicAPI]
public static partial class Sql
Expand Down Expand Up @@ -264,6 +266,41 @@ public static Guid NewGuid()
return Guid.NewGuid();
}

sealed class GuidToStringBuilder : IExtensionCallBuilder
{
public void Build(ISqExtensionBuilder builder)
{
var para = builder.GetExpression(0);

builder.ResultExpression = PseudoFunctions.MakeConvert(SqlDataType.String, SqlDataType.Guid, para);
}
}

/// <summary>
/// Converts a Guid to a normalized string in the format <c>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx</c>.
/// </summary>
/// <param name="guid">The guid to convert.</param>
/// <returns>The guid formatted to a string.</returns>
[CLSCompliant(false)]
[Expression(PN.SQLite, "lower((substr(hex({0}), 7, 2) || substr(hex({0}), 5, 2) || substr(hex({0}), 3, 2) || substr(hex({0}), 1, 2) || '-' || substr(hex({0}), 11, 2) || substr(hex({0}), 9, 2) || '-' || substr(hex({0}), 15, 2) || substr(hex({0}), 13, 2) || '-' || substr(hex({0}), 17, 4) || '-' || substr(hex({0}), 21, 12)))", IsNullable = IsNullableType.IfAnyParameterNullable, PreferServerSide = true)]
[Expression(PN.Access, "LCase(Mid(CStr({0}), 2, 36))", IsNullable = IsNullableType.IfAnyParameterNullable, PreferServerSide = true)]
[Expression(PN.PostgreSQL, "(Cast({0} as VarChar(36)))", IsNullable = IsNullableType.IfAnyParameterNullable, PreferServerSide = true)]
[Expression(PN.MariaDB, "Lower(Cast({0} as CHAR(36)))", IsNullable = IsNullableType.IfAnyParameterNullable, PreferServerSide = true)]
[Expression(PN.MySql, "Lower(Cast({0} as CHAR(36)))", IsNullable = IsNullableType.IfAnyParameterNullable, PreferServerSide = true)]
[Expression(PN.Informix, "Lower(To_Char({0}))", IsNullable = IsNullableType.IfAnyParameterNullable, PreferServerSide = true)]
[Expression(PN.DB2, "lower((substr(hex({0}), 7, 2) || substr(hex({0}), 5, 2) || substr(hex({0}), 3, 2) || substr(hex({0}), 1, 2) || '-' || substr(hex({0}), 11, 2) || substr(hex({0}), 9, 2) || '-' || substr(hex({0}), 15, 2) || substr(hex({0}), 13, 2) || '-' || substr(hex({0}), 17, 4) || '-' || substr(hex({0}), 21, 12)))", IsNullable = IsNullableType.IfAnyParameterNullable, PreferServerSide = true)]
[Expression(PN.Oracle, "lower((substr(rawtohex({0}), 7, 2) || substr(rawtohex({0}), 5, 2) || substr(rawtohex({0}), 3, 2) || substr(rawtohex({0}), 1, 2) || '-' || substr(rawtohex({0}), 11, 2) || substr(rawtohex({0}), 9, 2) || '-' || substr(rawtohex({0}), 15, 2) || substr(rawtohex({0}), 13, 2) || '-' || substr(rawtohex({0}), 17, 4) || '-' || substr(rawtohex({0}), 21, 12)))", IsNullable = IsNullableType.IfAnyParameterNullable, PreferServerSide = true)]
[Expression(PN.ClickHouse, "lower(toString({0}))", IsNullable = IsNullableType.IfAnyParameterNullable, PreferServerSide = true)]
[Expression(PN.SapHana, "Lower(Cast({0} as NVarChar(36)))", IsNullable = IsNullableType.IfAnyParameterNullable, PreferServerSide = true)]
[Expression(PN.Sybase, "Lower(Convert(NVarChar(36), {0}))", IsNullable = IsNullableType.IfAnyParameterNullable, PreferServerSide = true)]
[Expression(PN.SqlServer, "LOWER(CAST({0} AS char(36)))", IsNullable = IsNullableType.IfAnyParameterNullable, PreferServerSide = true)]
[Extension("", BuilderType = typeof(GuidToStringBuilder), PreferServerSide = true)]
jogibear9988 marked this conversation as resolved.
Show resolved Hide resolved
[return: NotNullIfNotNull(nameof(guid))]
public static string? GuidToNormalizedString(Guid? guid)
jogibear9988 marked this conversation as resolved.
Show resolved Hide resolved
{
return guid == null ? null : guid.ToString();
}

#endregion

#region Convert Functions
Expand Down
70 changes: 70 additions & 0 deletions Tests/Linq/UserTests/Issue4295Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System.Linq;
using FluentAssertions;
using LinqToDB;
using LinqToDB.Mapping;
using NUnit.Framework;
using System.Linq.Dynamic.Core;
using System.Linq.Dynamic.Core.CustomTypeProviders;
using System.Collections.Generic;
using System;
using LinqToDB.Data;

namespace Tests.UserTests
{
[TestFixture]
public class Issue4295Tests : TestBase
{
[Table]
public class InfeedAdvicePositionDTO
{
[Column] public Guid Id { get; set; }
}

[Test]
public void TestGuidToString([DataSources] string context)
{
using (var db = GetDataContext(context))
using (db.CreateLocalTable<InfeedAdvicePositionDTO>())
{
var expected = "193AE7F4-5309-4EEE-A746-27B28C7E30F3".ToLowerInvariant();

var a = new InfeedAdvicePositionDTO() { Id = Guid.Parse(expected) };
db.Insert(a);

var id = (from infeed in db.GetTable<InfeedAdvicePositionDTO>()
select Sql.GuidToNormalizedString(infeed.Id)).First();

Assert.AreEqual(expected, id);

var qryA = from infeed in db.GetTable<InfeedAdvicePositionDTO>()
where Sql.GuidToNormalizedString(infeed.Id)!.Contains("7f4-53")
select infeed;

var lA = qryA.ToList();
Assert.AreEqual(1, lA.Count);

var qryB = from infeed in db.GetTable<InfeedAdvicePositionDTO>()
where Sql.GuidToNormalizedString(infeed.Id)!.StartsWith("193ae")
select infeed;

var lB = qryB.ToList();
Assert.AreEqual(1, lB.Count);


var qryC = from infeed in db.GetTable<InfeedAdvicePositionDTO>()
where Sql.GuidToNormalizedString(infeed.Id)!.Contains("8f4-53")
select infeed;

var lC = qryC.ToList();
Assert.AreEqual(0, lC.Count);

var qryD = from infeed in db.GetTable<InfeedAdvicePositionDTO>()
where Sql.GuidToNormalizedString(infeed.Id)!.ToLower().StartsWith("293ae")
select infeed;

var lD = qryD.ToList();
Assert.AreEqual(0, lD.Count);
}
}
}
}