Skip to content

Commit affd440

Browse files
smnshtbricelam
andauthored
31355: SQLite: Add EF.Functions.Unhex (#31454)
Fixes #31355 Co-authored-by: Brice Lambson <[email protected]>
1 parent 1e26609 commit affd440

File tree

3 files changed

+86
-2
lines changed

3 files changed

+86
-2
lines changed

src/EFCore.Sqlite.Core/Extensions/SqliteDbFunctionsExtensions.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,33 @@ public static bool Glob(this DbFunctions _, string matchExpression, string patte
4343
public static string Hex(this DbFunctions _, byte[] bytes)
4444
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Hex)));
4545

46+
/// <summary>
47+
/// Maps to the SQLite <c>unhex</c> function which returns a BLOB representing decoding of the hexadecimal string.
48+
/// </summary>
49+
/// <remarks>
50+
/// See <see href="https://aka.ms/efcore-docs-database-functions">Database functions</see>, and
51+
/// <see href="https://aka.ms/efcore-docs-sqlite">Accessing SQLite databases with EF Core</see> for more information and examples.
52+
/// </remarks>
53+
/// <param name="_">The <see cref="DbFunctions" /> instance.</param>
54+
/// <param name="value">The hexadecimal string.</param>
55+
/// <returns>Decoded hexadecimal string as binary value.</returns>
56+
public static byte[] Unhex(this DbFunctions _, string value)
57+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Unhex)));
58+
59+
/// <summary>
60+
/// Maps to the SQLite <c>unhex</c> function which returns a BLOB representing decoding of the hexadecimal string.
61+
/// </summary>
62+
/// <remarks>
63+
/// See <see href="https://aka.ms/efcore-docs-database-functions">Database functions</see>, and
64+
/// <see href="https://aka.ms/efcore-docs-sqlite">Accessing SQLite databases with EF Core</see> for more information and examples.
65+
/// </remarks>
66+
/// <param name="_">The <see cref="DbFunctions" /> instance.</param>
67+
/// <param name="value">The hexadecimal string.</param>
68+
/// <param name="ignoreChars">Characters that are ignored in <paramref name="value"/>.</param>
69+
/// <returns>Decoded hexadecimal string as binary value.</returns>
70+
public static byte[] Unhex(this DbFunctions _, string value, string ignoreChars)
71+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Unhex)));
72+
4673
/// <summary>
4774
/// Maps to the SQLite <c>substr</c> function which returns a subarray of the specified value. The subarray starts
4875
/// at <paramref name="startIndex" /> and continues to the end of the value.

src/EFCore.Sqlite.Core/Query/Internal/SqliteHexMethodTranslator.cs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,15 @@ namespace Microsoft.EntityFrameworkCore.Sqlite.Query.Internal;
1313
/// </summary>
1414
public class SqliteHexMethodTranslator : IMethodCallTranslator
1515
{
16-
private static readonly MethodInfo MethodInfo = typeof(SqliteDbFunctionsExtensions)
16+
private static readonly MethodInfo HexMethodInfo = typeof(SqliteDbFunctionsExtensions)
1717
.GetMethod(nameof(SqliteDbFunctionsExtensions.Hex), new[] { typeof(DbFunctions), typeof(byte[]) })!;
1818

19+
private static readonly MethodInfo UnhexMethodInfo = typeof(SqliteDbFunctionsExtensions)
20+
.GetMethod(nameof(SqliteDbFunctionsExtensions.Unhex), new[] { typeof(DbFunctions), typeof(string) })!;
21+
22+
private static readonly MethodInfo UnhexWithIgnoreCharsMethodInfo = typeof(SqliteDbFunctionsExtensions)
23+
.GetMethod(nameof(SqliteDbFunctionsExtensions.Unhex), new[] { typeof(DbFunctions), typeof(string), typeof(string) })!;
24+
1925
private readonly ISqlExpressionFactory _sqlExpressionFactory;
2026

2127
/// <summary>
@@ -41,7 +47,7 @@ public SqliteHexMethodTranslator(ISqlExpressionFactory sqlExpressionFactory)
4147
IReadOnlyList<SqlExpression> arguments,
4248
IDiagnosticsLogger<DbLoggerCategory.Query> logger)
4349
{
44-
if (method.Equals(MethodInfo))
50+
if (method.Equals(HexMethodInfo))
4551
{
4652
return _sqlExpressionFactory.Function(
4753
"hex",
@@ -51,6 +57,17 @@ public SqliteHexMethodTranslator(ISqlExpressionFactory sqlExpressionFactory)
5157
typeof(string));
5258
}
5359

60+
if (method.Equals(UnhexMethodInfo)
61+
|| method.Equals(UnhexWithIgnoreCharsMethodInfo))
62+
{
63+
return _sqlExpressionFactory.Function(
64+
"unhex",
65+
arguments.Skip(1),
66+
nullable: true,
67+
arguments.Skip(1).Select(_ => true).ToArray(),
68+
typeof(byte[]));
69+
}
70+
5471
return null;
5572
}
5673
}

test/EFCore.Sqlite.FunctionalTests/BuiltInDataTypesSqliteTest.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,6 +1546,46 @@ SELECT hex("o"."Bytes")
15461546
Assert.Equal(expectedResults, results);
15471547
}
15481548

1549+
[ConditionalFact]
1550+
public virtual void Can_query_using_unhex_function()
1551+
{
1552+
using var context = CreateContext();
1553+
1554+
var results = context.Set<ObjectBackedDataTypes>()
1555+
.Select(e => EF.Functions.Unhex(EF.Functions.Hex(e.Bytes))).ToList();
1556+
1557+
AssertSql(
1558+
"""
1559+
SELECT unhex(hex("o"."Bytes"))
1560+
FROM "ObjectBackedDataTypes" AS "o"
1561+
""");
1562+
1563+
var expectedResults = context.Set<ObjectBackedDataTypes>().AsEnumerable()
1564+
.Select(e => e.Bytes).ToList();
1565+
1566+
Assert.Equal(expectedResults, results);
1567+
}
1568+
1569+
[ConditionalFact]
1570+
public virtual void Can_query_using_unhex_function_with_ignore_chars()
1571+
{
1572+
using var context = CreateContext();
1573+
1574+
var results = context.Set<ObjectBackedDataTypes>()
1575+
.Select(e => EF.Functions.Unhex(EF.Functions.Hex(e.Bytes) + "!?", "!?")).ToList();
1576+
1577+
AssertSql(
1578+
"""
1579+
SELECT unhex(COALESCE(hex("o"."Bytes"), '') || '!?', '!?')
1580+
FROM "ObjectBackedDataTypes" AS "o"
1581+
""");
1582+
1583+
var expectedResults = context.Set<ObjectBackedDataTypes>().AsEnumerable()
1584+
.Select(e => e.Bytes).ToList();
1585+
1586+
Assert.Equal(expectedResults, results);
1587+
}
1588+
15491589
[ConditionalFact]
15501590
public virtual void Can_query_using_substr_function()
15511591
{

0 commit comments

Comments
 (0)