Last active
April 15, 2023 01:03
-
-
Save JKamsker/4eda3e5f83fc2ce60702f0a92ea2c96b to your computer and use it in GitHub Desktop.
Code Snippets
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Problem: You want to inline arguments in a FormattableString. | |
Example: | |
return queryable.FromSqlInterpolated($@" | |
SELECT * | |
FROM {tableName} | |
WHERE dbo.compare({columnName}, {lowerString}) >= 0 | |
AND dbo.compare({columnName}, {upperString}) <= 0 | |
"); | |
This will result in a sql statement like this: | |
SELECT * | |
FROM @p0 | |
WHERE dbo.compare(@p1, @p2) >= 0 | |
AND dbo.compare(@p1, @p3) <= 0 | |
In this case, the sql server will fail, because it cannot parameterize table- and column names. | |
For this reason, we need to inline the arguments like this: | |
return queryable.FromSqlInterpolated(FormattableStringHelper.CreateInlined($@" | |
SELECT * | |
FROM {tableName:inline} | |
WHERE dbo.compare({columnName:inline}, {lowerString}) >= 0 | |
AND dbo.compare({columnName:inline}, {upperString}) <= 0 | |
")); | |
This will result in a sql statement like this: | |
SELECT * | |
FROM [dbo].[MyTable] | |
WHERE dbo.compare([MyColumn], @p0) >= 0 | |
AND dbo.compare([MyColumn], @p1) <= 0 | |
And the sql server will be happy. :) | |
*/ | |
public static class FormattableStringHelper | |
{ | |
private static readonly Regex _formatFinder = new(@"\{(\d+)(?::(.*?))?\}", RegexOptions.Compiled); | |
/// <summary> | |
/// Creates a new FormattableString with inlined arguments from the specified FormattableString. | |
/// {something:inline} will inline | |
/// </summary> | |
/// <remarks>{something:inline} will inline</remarks> | |
/// <param name="formattableString">The original FormattableString.</param> | |
/// <returns>A new FormattableString with inlined arguments.</returns> | |
public static FormattableString CreateInlined(FormattableString formattableString) | |
{ | |
var arguments = formattableString.GetArguments().ToList(); | |
var ignoredIndices = new List<int>(); | |
var lastIndex = 0; | |
var newString = _formatFinder.Replace(formattableString.Format, x => | |
{ | |
// Extract the argument index from the matched regex group | |
var argumentIndex = int.Parse(x.Groups[1].Value); | |
// inline: has 2 groups and group 2 is inline | |
var isInline = x.Groups.Count == 3 && x.Groups[2].Value == "inline"; | |
// If the argument index is valid, replace it with an empty string and add its index to ignoredIndices | |
if (argumentIndex < arguments.Count && isInline) | |
{ | |
ignoredIndices.Add(argumentIndex); | |
return arguments[argumentIndex]?.ToString() ?? string.Empty; | |
} | |
// Otherwise, return the original matched string | |
return $"{{{lastIndex++}}}"; | |
}); | |
// Create a new FormattableString with the remaining arguments | |
var newArguments = arguments.Where((arg, index) => !ignoredIndices.Contains(index)).ToArray(); | |
return FormattableStringFactory.Create(newString, newArguments); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment