-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Description
In relational, we have JsonScalarExpression (for extracting a scalar property out of a JSON document) and JsonQueryExpression (for extracting an object or array). These mainly follow the SQL Server function support (JSON_SCALAR() and JSON_QUERY()), but unless I'm mistaken both these functions were standardized in SQL/JSON, and are now supported e.g. by PostgreSQL as well - so that seems fine.
However, JsonQueryExpression is currently designed as a shaper-side expression. It does not extend SqlExpression (which represents scalars), although the JSON_QUERY() database function is nothing more than a simple scalar function returning text (which itself represents a structural object). In the query pipeilne, JsonQueryExpression temporarily exists before a scalar property (or another nested object) is bound on it, but it never actually makes it to SQL generation: when we apply the final projection, any JsonQueryExpression we find in the projection is converted to a JsonScalarExpression (code). Then, in SQL generation, we identify that this JsonScalarExpression has a special type mapping (SqlServerOwnedJsonTypeMapping) and emit JsonQueryExpression. This is a very hacky state of affairs - JsonScalarExpression should not be used to represent object access (only scalar), and JsonQueryExpression should simply flow through to SQL generation.
This also causes issues e.g. in complex JSON equality, where e.g. two JsonQueryExpressions compared to each other (for when two nested objects in a JSON document are compared) must also be converted to a hacked JsonScalarExpression in a similar way.
JsonQueryExpression should be a pure server-side (SQL) expression, whose type mapping should represent the JSON string, and know nothing about the structural type being shaped; that shaper-side information should live in a separate, shaper-side expression.