Skip to content

Commit 0bf88c5

Browse files
authored
Support JsonOverlaps function (#1985)
* Support JsonOverlaps function * Remove test logging fixture helper call * Fix typo error * Introduce JsonOverlaps version flag * Removal of unused code * Renamed parameters
1 parent beaf6eb commit 0bf88c5

7 files changed

Lines changed: 155 additions & 1 deletion

File tree

src/EFCore.MySql/Extensions/MySqlJsonDbFunctionsExtensions.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,20 @@ public static T JsonExtract<T>(
8484
[NotNull] params string[] paths)
8585
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(JsonExtract)));
8686

87+
/// <summary>
88+
/// Checks if <paramref name="json1"/> overlaps <paramref name="json2"/>.
89+
/// </summary>
90+
/// <param name="_">DbFunctions instance</param>
91+
/// <param name="json1">
92+
/// A JSON column or value. Can be a JSON DOM object, a string property mapped to JSON, or a user POCO mapped to JSON.
93+
/// </param>
94+
/// <param name="json2">
95+
/// A JSON column or value. Can be a JSON DOM object, a string, or a user POCO mapped to JSON.
96+
/// </param>
97+
public static bool JsonOverlaps(
98+
[CanBeNull] this DbFunctions _, [NotNull] object json1, [NotNull] object json2)
99+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(JsonOverlaps)));
100+
87101
/// <summary>
88102
/// Checks if <paramref name="json"/> contains <paramref name="candidate"/>.
89103
/// </summary>

src/EFCore.MySql/Infrastructure/MariaDbServerVersion.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ internal MariaDbServerVersionSupport([NotNull] ServerVersion serverVersion)
9393
public override bool LimitWithNonConstantValue => false;
9494
public override bool JsonTable => ServerVersion.Version >= new Version(10, 6, 0); // Since there seems to be no implicit LATERAL support for JSON_TABLE, this is pretty useless except for cases where the JSON is provided by a parameter instead of a column of an outer table.
9595
public override bool JsonValue => true;
96+
public override bool JsonOverlaps => ServerVersion.Version >= new Version(10, 9, 0);
9697
public override bool Values => ServerVersion.Version >= new Version(10, 3, 3);
9798
public override bool ValuesWithRows => false;
9899
public override bool WhereSubqueryReferencesOuterQuery => false;

src/EFCore.MySql/Infrastructure/MySqlServerVersion.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ internal MySqlServerVersionSupport([NotNull] ServerVersion serverVersion)
9494
public override bool LimitWithNonConstantValue => false;
9595
public override bool JsonTable => ServerVersion.Version >= new Version(8, 0, 4);
9696
public override bool JsonValue => ServerVersion.Version >= new Version(8, 0, 21);
97+
public override bool JsonOverlaps => ServerVersion.Version >= new Version(8, 0, 0);
9798
public override bool Values => false;
9899
public override bool ValuesWithRows => ServerVersion.Version >= new Version(8, 0, 19);
99100
public override bool WhereSubqueryReferencesOuterQuery => false;

src/EFCore.MySql/Infrastructure/ServerVersionSupport.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public virtual bool PropertyOrVersion(string propertyNameOrServerVersion)
5959
public virtual bool CrossApply => false;
6060
public virtual bool OuterReferenceInMultiLevelSubquery => false;
6161
public virtual bool Json => false;
62+
public virtual bool JsonOverlaps => false;
6263
public virtual bool GeneratedColumns => false;
6364
public virtual bool NullableGeneratedColumns => false;
6465
public virtual bool ParenthesisEnclosedGeneratedColumnExpressions => false;

src/EFCore.MySql/Query/ExpressionTranslators/Internal/MySqlJsonDbFunctionsTranslator.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ public virtual SqlExpression Translate(
9090
method.ReturnType,
9191
_sqlExpressionFactory.FindMapping(method.ReturnType, "json"),
9292
false),
93+
nameof(MySqlJsonDbFunctionsExtensions.JsonOverlaps)
94+
=> _sqlExpressionFactory.NullableFunction(
95+
"JSON_OVERLAPS",
96+
new[] { Json(args[0]), args[1] },
97+
typeof(bool)),
9398
nameof(MySqlJsonDbFunctionsExtensions.JsonContains)
9499
=> _sqlExpressionFactory.NullableFunction(
95100
"JSON_CONTAINS",

test/EFCore.MySql.FunctionalTests/Query/JsonMicrosoftDomQueryTest.cs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,72 @@ WHERE JSON_UNQUOTE(`j`.`CustomerElement`) = 'foo'
320320

321321
#region Functions
322322

323+
[ConditionalFact]
324+
[SupportedServerVersionCondition(nameof(ServerVersionSupport.JsonOverlaps))]
325+
public void JsonOverlaps_with_json_element()
326+
{
327+
using var ctx = CreateContext();
328+
var element = JsonDocument.Parse(@"{""Name"": ""Joe"", ""Age"": -1}").RootElement;
329+
var count = ctx.JsonEntities.Count(e =>
330+
EF.Functions.JsonOverlaps(e.CustomerElement, element));
331+
332+
Assert.Equal(1, count);
333+
AssertSql(
334+
$@"@__element_1='{{""Name"":""Joe"",""Age"":-1}}' (Nullable = false) (Size = 4000)
335+
336+
SELECT COUNT(*)
337+
FROM `JsonEntities` AS `j`
338+
WHERE JSON_OVERLAPS(`j`.`CustomerElement`, {InsertJsonConvert("@__element_1")})");
339+
}
340+
341+
[ConditionalFact]
342+
[SupportedServerVersionCondition(nameof(ServerVersionSupport.JsonOverlaps))]
343+
public void JsonOverlaps_with_string()
344+
{
345+
using var ctx = CreateContext();
346+
var count = ctx.JsonEntities.Count(e =>
347+
EF.Functions.JsonOverlaps(e.CustomerElement, @"{""Name"": ""Joe"", ""Age"": -1}"));
348+
349+
Assert.Equal(1, count);
350+
AssertSql(
351+
@"SELECT COUNT(*)
352+
FROM `JsonEntities` AS `j`
353+
WHERE JSON_OVERLAPS(`j`.`CustomerElement`, '{""Name"": ""Joe"", ""Age"": -1}')");
354+
}
355+
356+
[ConditionalFact]
357+
[SupportedServerVersionCondition(nameof(ServerVersionSupport.JsonOverlaps))]
358+
public void JsonOverlaps_using_JsonExtract_with_json_element()
359+
{
360+
using var ctx = CreateContext();
361+
var element = JsonDocument.Parse(@"[3,-1]").RootElement;
362+
var count = ctx.JsonEntities.Count(e =>
363+
EF.Functions.JsonOverlaps(EF.Functions.JsonExtract<string[]>(e.CustomerElement, "$.Statistics.Nested.IntArray"), element));
364+
365+
Assert.Equal(1, count);
366+
AssertSql(
367+
$@"@__element_1='[3,-1]' (Nullable = false) (Size = 4000)
368+
369+
SELECT COUNT(*)
370+
FROM `JsonEntities` AS `j`
371+
WHERE JSON_OVERLAPS(JSON_EXTRACT(`j`.`CustomerElement`, '$.Statistics.Nested.IntArray'), {InsertJsonConvert("@__element_1")})");
372+
}
373+
374+
[ConditionalFact]
375+
[SupportedServerVersionCondition(nameof(ServerVersionSupport.JsonOverlaps))]
376+
public void JsonOverlaps_using_JsonExtract_with_json_string()
377+
{
378+
using var ctx = CreateContext();
379+
var count = ctx.JsonEntities.Count(e =>
380+
EF.Functions.JsonOverlaps(EF.Functions.JsonExtract<string[]>(e.CustomerElement, "$.Statistics.Nested.IntArray"), @"[3,-1]"));
381+
382+
Assert.Equal(1, count);
383+
AssertSql(
384+
$@"SELECT COUNT(*)
385+
FROM `JsonEntities` AS `j`
386+
WHERE JSON_OVERLAPS(JSON_EXTRACT(`j`.`CustomerElement`, '$.Statistics.Nested.IntArray'), '[3,-1]')");
387+
}
388+
323389
[Fact]
324390
public void JsonContains_with_json_element()
325391
{

test/EFCore.MySql.FunctionalTests/Query/JsonNewtonsoftDomQueryTest.cs

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,73 @@ WHERE JSON_UNQUOTE(`j`.`CustomerJToken`) = 'foo'
346346
LIMIT 2");
347347
}
348348

349-
#region Functions
349+
#region Functions
350+
351+
[ConditionalFact]
352+
[SupportedServerVersionCondition(nameof(ServerVersionSupport.JsonOverlaps))]
353+
public void JsonOverlaps_with_json_element()
354+
{
355+
using var ctx = CreateContext();
356+
var element = JObject.Parse(@"{""Name"": ""Joe"", ""Age"": -1}").Root;
357+
var count = ctx.JsonEntities.Count(e =>
358+
EF.Functions.JsonOverlaps(e.CustomerJToken, element));
359+
360+
Assert.Equal(1, count);
361+
AssertSql(
362+
$@"@__element_1='{{""Name"":""Joe"",""Age"":-1}}' (Size = 4000)
363+
364+
SELECT COUNT(*)
365+
FROM `JsonEntities` AS `j`
366+
WHERE JSON_OVERLAPS(`j`.`CustomerJToken`, {InsertJsonConvert("@__element_1")})");
367+
}
368+
369+
[ConditionalFact]
370+
[SupportedServerVersionCondition(nameof(ServerVersionSupport.JsonOverlaps))]
371+
public void JsonOverlaps_with_string()
372+
{
373+
using var ctx = CreateContext();
374+
var count = ctx.JsonEntities.Count(e =>
375+
EF.Functions.JsonOverlaps(e.CustomerJToken, @"{""Name"": ""Joe"", ""Age"": -1}"));
376+
377+
Assert.Equal(1, count);
378+
AssertSql(
379+
@"SELECT COUNT(*)
380+
FROM `JsonEntities` AS `j`
381+
WHERE JSON_OVERLAPS(`j`.`CustomerJToken`, '{""Name"": ""Joe"", ""Age"": -1}')");
382+
}
383+
384+
[ConditionalFact]
385+
[SupportedServerVersionCondition(nameof(ServerVersionSupport.JsonOverlaps))]
386+
public void JsonOverlaps_using_JsonExtract_with_json_element()
387+
{
388+
using var ctx = CreateContext();
389+
var element = JArray.Parse(@"[3,-1]");
390+
var count = ctx.JsonEntities.Count(e =>
391+
EF.Functions.JsonOverlaps(EF.Functions.JsonExtract<string[]>(e.CustomerJToken, "$.Statistics.Nested.IntArray"), element));
392+
393+
Assert.Equal(1, count);
394+
AssertSql(
395+
$@"@__element_1='[3,-1]' (Size = 4000)
396+
397+
SELECT COUNT(*)
398+
FROM `JsonEntities` AS `j`
399+
WHERE JSON_OVERLAPS(JSON_EXTRACT(`j`.`CustomerJToken`, '$.Statistics.Nested.IntArray'), {InsertJsonConvert("@__element_1")})");
400+
}
401+
402+
[ConditionalFact]
403+
[SupportedServerVersionCondition(nameof(ServerVersionSupport.JsonOverlaps))]
404+
public void JsonOverlaps_using_JsonExtract_with_json_string()
405+
{
406+
using var ctx = CreateContext();
407+
var count = ctx.JsonEntities.Count(e =>
408+
EF.Functions.JsonOverlaps(EF.Functions.JsonExtract<string[]>(e.CustomerJToken, "$.Statistics.Nested.IntArray"), @"[3,-1]"));
409+
410+
Assert.Equal(1, count);
411+
AssertSql(
412+
$@"SELECT COUNT(*)
413+
FROM `JsonEntities` AS `j`
414+
WHERE JSON_OVERLAPS(JSON_EXTRACT(`j`.`CustomerJToken`, '$.Statistics.Nested.IntArray'), '[3,-1]')");
415+
}
350416

351417
[Fact]
352418
public void JsonContains_with_json_element()

0 commit comments

Comments
 (0)