Skip to content

Commit

Permalink
Add translations for string.Substring with one arg (#24746)
Browse files Browse the repository at this point in the history
Fixes #20173
  • Loading branch information
stevendarby committed Apr 30, 2021
1 parent 9e1289d commit 67a5d16
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 41 deletions.
17 changes: 15 additions & 2 deletions src/EFCore.Cosmos/Query/Internal/StringMethodTranslator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ private static readonly MethodInfo _trimEndMethodInfoWithCharArrayArg
private static readonly MethodInfo _trimMethodInfoWithCharArrayArg
= typeof(string).GetRequiredRuntimeMethod(nameof(string.Trim), new[] { typeof(char[]) });

private static readonly MethodInfo _substringMethodInfo
private static readonly MethodInfo _substringMethodInfoWithOneArg
= typeof(string).GetRequiredRuntimeMethod(nameof(string.Substring), new[] { typeof(int) });

private static readonly MethodInfo _substringMethodInfoWithTwoArgs
= typeof(string).GetRequiredRuntimeMethod(nameof(string.Substring), new[] { typeof(int), typeof(int) });

private static readonly MethodInfo _firstOrDefaultMethodInfoWithoutArgs
Expand Down Expand Up @@ -156,7 +159,17 @@ public StringMethodTranslator(ISqlExpressionFactory sqlExpressionFactory)
return TranslateSystemFunction("TRIM", method.ReturnType, instance);
}

if (_substringMethodInfo.Equals(method))
if (_substringMethodInfoWithOneArg.Equals(method))
{
return TranslateSystemFunction(
"SUBSTRING",
method.ReturnType,
instance,
arguments[0],
TranslateSystemFunction("LENGTH", typeof(int), instance));
}

if (_substringMethodInfoWithTwoArgs.Equals(method))
{
return TranslateSystemFunction("SUBSTRING", method.ReturnType, instance, arguments[0], arguments[1]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ private static readonly MethodInfo _toLowerMethodInfo
private static readonly MethodInfo _toUpperMethodInfo
= typeof(string).GetRequiredRuntimeMethod(nameof(string.ToUpper), Array.Empty<Type>());

private static readonly MethodInfo _substringMethodInfo
private static readonly MethodInfo _substringMethodInfoWithOneArg
= typeof(string).GetRequiredRuntimeMethod(nameof(string.Substring), new[] { typeof(int) });

private static readonly MethodInfo _substringMethodInfoWithTwoArgs
= typeof(string).GetRequiredRuntimeMethod(nameof(string.Substring), new[] { typeof(int), typeof(int) });

private static readonly MethodInfo _isNullOrEmptyMethodInfo
Expand Down Expand Up @@ -190,7 +193,30 @@ public SqlServerStringMethodTranslator(ISqlExpressionFactory sqlExpressionFactor
instance.TypeMapping);
}

if (_substringMethodInfo.Equals(method))
if (_substringMethodInfoWithOneArg.Equals(method))
{
return _sqlExpressionFactory.Function(
"SUBSTRING",
new[]
{
instance,
_sqlExpressionFactory.Add(
arguments[0],
_sqlExpressionFactory.Constant(1)),
_sqlExpressionFactory.Function(
"LEN",
new[] { instance },
nullable: true,
argumentsPropagateNullability: new[] { true },
typeof(int))
},
nullable: true,
argumentsPropagateNullability: new[] { true, true, true },
method.ReturnType,
instance.TypeMapping);
}

if (_substringMethodInfoWithTwoArgs.Equals(method))
{
return _sqlExpressionFactory.Function(
"SUBSTRING",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ private static readonly MethodInfo _toLowerMethodInfo
private static readonly MethodInfo _toUpperMethodInfo
= typeof(string).GetRequiredRuntimeMethod(nameof(string.ToUpper), Array.Empty<Type>());

private static readonly MethodInfo _substringMethodInfo
private static readonly MethodInfo _substringMethodInfoWithOneArg
= typeof(string).GetRequiredRuntimeMethod(nameof(string.Substring), new[] { typeof(int) });

private static readonly MethodInfo _substringMethodInfoWithTwoArgs
= typeof(string).GetRequiredRuntimeMethod(nameof(string.Substring), new[] { typeof(int), typeof(int) });

private static readonly MethodInfo _isNullOrWhiteSpaceMethodInfo
Expand Down Expand Up @@ -170,7 +173,18 @@ public SqliteStringMethodTranslator(ISqlExpressionFactory sqlExpressionFactory)
instance.TypeMapping);
}

if (_substringMethodInfo.Equals(method))
if (_substringMethodInfoWithOneArg.Equals(method))
{
return _sqlExpressionFactory.Function(
"substr",
new[] { instance, _sqlExpressionFactory.Add(arguments[0], _sqlExpressionFactory.Constant(1)) },
nullable: true,
argumentsPropagateNullability: new[] { true, true },
method.ReturnType,
instance.TypeMapping);
}

if (_substringMethodInfoWithTwoArgs.Equals(method))
{
return _sqlExpressionFactory.Function(
"substr",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -745,39 +745,71 @@ FROM root c
WHERE ((c[""Discriminator""] = ""Customer"") AND (c[""CustomerID""] = ""ALFKI""))");
}

public override async Task Substring_with_zero_startindex(bool async)
public override async Task Substring_with_one_arg_with_zero_startindex(bool async)
{
await base.Substring_with_zero_startindex(async);
await base.Substring_with_one_arg_with_zero_startindex(async);

AssertSql(
@"SELECT c[""ContactName""]
FROM root c
WHERE ((c[""Discriminator""] = ""Customer"") AND (SUBSTRING(c[""CustomerID""], 0, LENGTH(c[""CustomerID""])) = ""ALFKI""))");
}

public override async Task Substring_with_one_arg_with_constant(bool async)
{
await base.Substring_with_one_arg_with_constant(async);

AssertSql(
@"SELECT c[""ContactName""]
FROM root c
WHERE ((c[""Discriminator""] = ""Customer"") AND (SUBSTRING(c[""CustomerID""], 1, LENGTH(c[""CustomerID""])) = ""LFKI""))");
}

public override async Task Substring_with_one_arg_with_closure(bool async)
{
await base.Substring_with_one_arg_with_closure(async);

AssertSql(
@"@__start_0='2'
SELECT c[""ContactName""]
FROM root c
WHERE ((c[""Discriminator""] = ""Customer"") AND (SUBSTRING(c[""CustomerID""], @__start_0, LENGTH(c[""CustomerID""])) = ""FKI""))");
}

public override async Task Substring_with_two_args_with_zero_startindex(bool async)
{
await base.Substring_with_two_args_with_zero_startindex(async);

AssertSql(
@"SELECT SUBSTRING(c[""ContactName""], 0, 3) AS c
FROM root c
WHERE ((c[""Discriminator""] = ""Customer"") AND (c[""CustomerID""] = ""ALFKI""))");
}

public override async Task Substring_with_zero_length(bool async)
public override async Task Substring_with_two_args_with_zero_length(bool async)
{
await base.Substring_with_zero_length(async);
await base.Substring_with_two_args_with_zero_length(async);

AssertSql(
@"SELECT SUBSTRING(c[""ContactName""], 2, 0) AS c
FROM root c
WHERE ((c[""Discriminator""] = ""Customer"") AND (c[""CustomerID""] = ""ALFKI""))");
}

public override async Task Substring_with_constant(bool async)
public override async Task Substring_with_two_args_with_constant(bool async)
{
await base.Substring_with_constant(async);
await base.Substring_with_two_args_with_constant(async);

AssertSql(
@"SELECT SUBSTRING(c[""ContactName""], 1, 3) AS c
FROM root c
WHERE ((c[""Discriminator""] = ""Customer"") AND (c[""CustomerID""] = ""ALFKI""))");
}

public override async Task Substring_with_closure(bool async)
public override async Task Substring_with_two_args_with_closure(bool async)
{
await base.Substring_with_closure(async);
await base.Substring_with_two_args_with_closure(async);

AssertSql(
@"@__start_0='2'
Expand All @@ -787,9 +819,9 @@ FROM root c
WHERE ((c[""Discriminator""] = ""Customer"") AND (c[""CustomerID""] = ""ALFKI""))");
}

public override async Task Substring_with_Index_of(bool async)
public override async Task Substring_with_two_args_with_Index_of(bool async)
{
await base.Substring_with_Index_of(async);
await base.Substring_with_two_args_with_Index_of(async);

AssertSql(
@"SELECT c[""ContactName""]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1322,7 +1322,42 @@ public virtual Task Replace_with_emptystring(bool async)

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Substring_with_zero_startindex(bool async)
public virtual Task Substring_with_one_arg_with_zero_startindex(bool async)
{
return AssertQuery(
async,
ss => ss.Set<Customer>()
.Where(c => c.CustomerID.Substring(0) == "ALFKI")
.Select(c => c.ContactName));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Substring_with_one_arg_with_constant(bool async)
{
return AssertQuery(
async,
ss => ss.Set<Customer>()
.Where(c => c.CustomerID.Substring(1) == "LFKI")
.Select(c => c.ContactName));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Substring_with_one_arg_with_closure(bool async)
{
var start = 2;

return AssertQuery(
async,
ss => ss.Set<Customer>()
.Where(c => c.CustomerID.Substring(start) == "FKI")
.Select(c => c.ContactName));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Substring_with_two_args_with_zero_startindex(bool async)
{
return AssertQuery(
async,
Expand All @@ -1331,7 +1366,7 @@ public virtual Task Substring_with_zero_startindex(bool async)

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Substring_with_zero_length(bool async)
public virtual Task Substring_with_two_args_with_zero_length(bool async)
{
return AssertQuery(
async,
Expand All @@ -1340,7 +1375,7 @@ public virtual Task Substring_with_zero_length(bool async)

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Substring_with_constant(bool async)
public virtual Task Substring_with_two_args_with_constant(bool async)
{
return AssertQuery(
async,
Expand All @@ -1349,7 +1384,7 @@ public virtual Task Substring_with_constant(bool async)

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Substring_with_closure(bool async)
public virtual Task Substring_with_two_args_with_closure(bool async)
{
var start = 2;

Expand All @@ -1360,7 +1395,7 @@ public virtual Task Substring_with_closure(bool async)

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Substring_with_Index_of(bool async)
public virtual Task Substring_with_two_args_with_Index_of(bool async)
{
return AssertQuery(
async,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1297,39 +1297,71 @@ FROM [Customers] AS [c]
WHERE [c].[CustomerID] = N'ALFKI'");
}

public override async Task Substring_with_zero_startindex(bool async)
public override async Task Substring_with_one_arg_with_zero_startindex(bool async)
{
await base.Substring_with_zero_startindex(async);
await base.Substring_with_one_arg_with_zero_startindex(async);

AssertSql(
@"SELECT [c].[ContactName]
FROM [Customers] AS [c]
WHERE SUBSTRING([c].[CustomerID], 0 + 1, LEN([c].[CustomerID])) = N'ALFKI'");
}

public override async Task Substring_with_one_arg_with_constant(bool async)
{
await base.Substring_with_one_arg_with_constant(async);

AssertSql(
@"SELECT [c].[ContactName]
FROM [Customers] AS [c]
WHERE SUBSTRING([c].[CustomerID], 1 + 1, LEN([c].[CustomerID])) = N'LFKI'");
}

public override async Task Substring_with_one_arg_with_closure(bool async)
{
await base.Substring_with_one_arg_with_closure(async);

AssertSql(
@"@__start_0='2'
SELECT [c].[ContactName]
FROM [Customers] AS [c]
WHERE SUBSTRING([c].[CustomerID], @__start_0 + 1, LEN([c].[CustomerID])) = N'FKI'");
}

public override async Task Substring_with_two_args_with_zero_startindex(bool async)
{
await base.Substring_with_two_args_with_zero_startindex(async);

AssertSql(
@"SELECT SUBSTRING([c].[ContactName], 0 + 1, 3)
FROM [Customers] AS [c]
WHERE [c].[CustomerID] = N'ALFKI'");
}

public override async Task Substring_with_zero_length(bool async)
public override async Task Substring_with_two_args_with_zero_length(bool async)
{
await base.Substring_with_zero_length(async);
await base.Substring_with_two_args_with_zero_length(async);

AssertSql(
@"SELECT SUBSTRING([c].[ContactName], 2 + 1, 0)
FROM [Customers] AS [c]
WHERE [c].[CustomerID] = N'ALFKI'");
}

public override async Task Substring_with_constant(bool async)
public override async Task Substring_with_two_args_with_constant(bool async)
{
await base.Substring_with_constant(async);
await base.Substring_with_two_args_with_constant(async);

AssertSql(
@"SELECT SUBSTRING([c].[ContactName], 1 + 1, 3)
FROM [Customers] AS [c]
WHERE [c].[CustomerID] = N'ALFKI'");
}

public override async Task Substring_with_closure(bool async)
public override async Task Substring_with_two_args_with_closure(bool async)
{
await base.Substring_with_closure(async);
await base.Substring_with_two_args_with_closure(async);

AssertSql(
@"@__start_0='2'
Expand All @@ -1339,9 +1371,9 @@ FROM [Customers] AS [c]
WHERE [c].[CustomerID] = N'ALFKI'");
}

public override async Task Substring_with_Index_of(bool async)
public override async Task Substring_with_two_args_with_Index_of(bool async)
{
await base.Substring_with_Index_of(async);
await base.Substring_with_two_args_with_Index_of(async);

AssertSql(
@"SELECT SUBSTRING([c].[ContactName], CASE
Expand Down
Loading

0 comments on commit 67a5d16

Please sign in to comment.