Skip to content

Commit

Permalink
Fix JSON operations directly on the root (column)
Browse files Browse the repository at this point in the history
  • Loading branch information
roji committed Jun 12, 2020
1 parent 91c2432 commit eda8129
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,20 @@ public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method
return null;
}

// The root of the JSON expression is a ColumnExpression. We wrap that with an empty traversal
// expression (col #>> '{}'); subsequent traversals will gradually append the path into that.
// Note that it's possible to call methods such as GetString() directly on the root, and the
// empty traversal is necessary to properly convert it to a text.
instance = instance is ColumnExpression columnExpression
? _sqlExpressionFactory.JsonTraversal(
columnExpression, returnsText: false, typeof(string), mapping)
: instance;

if (method == GetProperty || method == ArrayIndexer)
{
// The first time we see a JSON traversal it's on a column - create a JsonTraversalExpression.
// Traversals on top of that get appended into the same expression.
return instance is ColumnExpression columnExpression
? _sqlExpressionFactory.JsonTraversal(columnExpression, arguments, false, typeof(string), mapping)
: instance is PostgresJsonTraversalExpression prevPathTraversal
? prevPathTraversal.Append(_sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[0]))
: null;
return instance is PostgresJsonTraversalExpression prevPathTraversal
? prevPathTraversal.Append(_sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[0]))
: null;
}

if (GetMethods.Contains(method.Name) &&
Expand Down
7 changes: 7 additions & 0 deletions src/EFCore.PG/Query/Internal/NpgsqlSqlExpressionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ public virtual PostgresILikeExpression ILike(
[CanBeNull] SqlExpression escapeChar = null)
=> (PostgresILikeExpression)ApplyDefaultTypeMapping(new PostgresILikeExpression(match, pattern, escapeChar, null));

public virtual PostgresJsonTraversalExpression JsonTraversal(
[NotNull] SqlExpression expression,
bool returnsText,
[NotNull] Type type,
[CanBeNull] RelationalTypeMapping typeMapping = null)
=> JsonTraversal(expression, Array.Empty<SqlExpression>(), returnsText, type, typeMapping);

public virtual PostgresJsonTraversalExpression JsonTraversal(
[NotNull] SqlExpression expression,
[NotNull] IEnumerable<SqlExpression> path,
Expand Down
28 changes: 22 additions & 6 deletions test/EFCore.PG.FunctionalTests/Query/JsonDomQueryTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,19 @@ WHERE CAST(j.""CustomerElement""#>>'{Statistics,Nested,SomeNullableGuid}' AS uui
LIMIT 2");
}

[Fact] // #1415
public void Where_root_value()
{
using var ctx = CreateContext();
_ = ctx.JsonbEntities.Single(e => e.CustomerElement.GetString() == "foo");

AssertSql(
@"SELECT j.""Id"", j.""CustomerDocument"", j.""CustomerElement""
FROM ""JsonbEntities"" AS j
WHERE j.""CustomerElement""#>>'{}' = 'foo'
LIMIT 2");
}

#region Functions

[Fact]
Expand Down Expand Up @@ -501,15 +514,16 @@ public JsonDomQueryContext(DbContextOptions options) : base(options) {}

public static void Seed(JsonDomQueryContext context)
{
var customer1 = CreateCustomer1();
var customer2 = CreateCustomer2();
var (customer1, customer2, customer3) = (CreateCustomer1(), CreateCustomer2(), CreateCustomer3());

context.JsonbEntities.AddRange(
new JsonbEntity { Id = 1, CustomerDocument = customer1, CustomerElement = customer1.RootElement},
new JsonbEntity { Id = 2, CustomerDocument = customer2, CustomerElement = customer2.RootElement});
new JsonbEntity { Id = 1, CustomerDocument = customer1, CustomerElement = customer1.RootElement },
new JsonbEntity { Id = 2, CustomerDocument = customer2, CustomerElement = customer2.RootElement },
new JsonbEntity { Id = 3, CustomerDocument = customer3, CustomerElement = customer3.RootElement });
context.JsonEntities.AddRange(
new JsonEntity { Id = 1, CustomerDocument = customer1, CustomerElement = customer1.RootElement},
new JsonEntity { Id = 2, CustomerDocument = customer2, CustomerElement = customer2.RootElement});
new JsonEntity { Id = 1, CustomerDocument = customer1, CustomerElement = customer1.RootElement },
new JsonEntity { Id = 2, CustomerDocument = customer2, CustomerElement = customer2.RootElement },
new JsonEntity { Id = 3, CustomerDocument = customer3, CustomerElement = customer3.RootElement });
context.SaveChanges();

static JsonDocument CreateCustomer1() => JsonDocument.Parse(@"
Expand Down Expand Up @@ -572,6 +586,8 @@ static JsonDocument CreateCustomer2() => JsonDocument.Parse(@"
}
]
}");

static JsonDocument CreateCustomer3() => JsonDocument.Parse(@"""foo""");
}
}

Expand Down

0 comments on commit eda8129

Please sign in to comment.