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

Add translations for string.Substring with one arg #24746

Merged
merged 3 commits into from
Apr 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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