Skip to content

Instantly share code, notes, and snippets.

@JKamsker
Last active April 15, 2023 01:03
Show Gist options
  • Save JKamsker/4eda3e5f83fc2ce60702f0a92ea2c96b to your computer and use it in GitHub Desktop.
Save JKamsker/4eda3e5f83fc2ce60702f0a92ea2c96b to your computer and use it in GitHub Desktop.
Code Snippets
/*
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