Repository: edgedb/edgedb

Issue:
`<json>array_agg(...)` returns json objects containing implicit fields
- EdgeDB Version: 3.0-dev.7023+local
- EdgeDB CLI Version: n/a
- OS Version: n/a

The result of doing `array_agg` of a set without a shape then casting to json, returns json objects containing `__tid__` and `__tname__` keys. The json cast or `array_agg` alone, return the expected result without those keys.

Steps to Reproduce:

```edgeql
select <json>array_agg(Movie);
```

```json
[
  {
    "id": "059ed7da-5af1-11ed-8d35-3fca3d6effef",
    "__tid__": "0091bcc1-5af1-11ed-86bc-039fd26f02d8",
    "__tname__": "default::Movie"
  },
  {
    "id": "059f2f5a-5af1-11ed-8d35-93425cf5e03a",
    "__tid__": "0091bcc1-5af1-11ed-86bc-039fd26f02d8",
    "__tname__": "default::Movie"
  },
...
```



Discussion:

Resolving patch:
diff --git a/edb/edgeql/compiler/casts.py b/edb/edgeql/compiler/casts.py
--- a/edb/edgeql/compiler/casts.py
+++ b/edb/edgeql/compiler/casts.py
@@ -151,11 +151,7 @@ def compile_cast(
     ):
         # JSON casts of objects are special: we want the full shape
         # and not just an identity.
-        with ctx.new() as subctx:
-            subctx.implicit_id_in_shapes = False
-            subctx.implicit_tid_in_shapes = False
-            subctx.implicit_tname_in_shapes = False
-            viewgen.late_compile_view_shapes(ir_set, ctx=subctx)
+        viewgen.late_compile_view_shapes(ir_set, ctx=ctx)
     else:
         if orig_stype.issubclass(ctx.env.schema, json_t) and new_stype.is_enum(
             ctx.env.schema
diff --git a/edb/edgeql/compiler/expr.py b/edb/edgeql/compiler/expr.py
--- a/edb/edgeql/compiler/expr.py
+++ b/edb/edgeql/compiler/expr.py
@@ -545,11 +545,7 @@ def compile_TypeCast(
     target_typeref = typegen.type_to_typeref(target_stype, env=ctx.env)
     ir_expr: Union[irast.Set, irast.Expr]
 
-    if (isinstance(expr.expr, qlast.Array) and not expr.expr.elements and
-            irtyputils.is_array(target_typeref)):
-        ir_expr = irast.Array(elements=[], typeref=target_typeref)
-
-    elif isinstance(expr.expr, qlast.Parameter):
+    if isinstance(expr.expr, qlast.Parameter):
         pt = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx)
 
         param_name = expr.expr.name
@@ -628,20 +624,32 @@ def compile_TypeCast(
 
         return param
 
-    else:
-        with ctx.new() as subctx:
-            if target_stype.contains_json(subctx.env.schema):
-                # JSON wants type shapes and acts as an output sink.
-                subctx.expr_exposed = context.Exposure.EXPOSED
-                subctx.inhibit_implicit_limit = True
-                subctx.implicit_id_in_shapes = False
-                subctx.implicit_tid_in_shapes = False
-                subctx.implicit_tname_in_shapes = False
+    with ctx.new() as subctx:
+        if target_stype.contains_json(subctx.env.schema):
+            # JSON wants type shapes and acts as an output sink.
+            subctx.expr_exposed = context.Exposure.EXPOSED
+            subctx.inhibit_implicit_limit = True
+            subctx.implicit_id_in_shapes = False
+            subctx.implicit_tid_in_shapes = False
+            subctx.implicit_tname_in_shapes = False
+
+        if (
+            isinstance(expr.expr, qlast.Array)
+            and not expr.expr.elements
+            and irtyputils.is_array(target_typeref)
+        ):
+            ir_expr = irast.Array(elements=[], typeref=target_typeref)
+        else:
             ir_expr = dispatch.compile(expr.expr, ctx=subctx)
 
-    res = casts.compile_cast(
-        ir_expr, target_stype, cardinality_mod=expr.cardinality_mod,
-        ctx=ctx, srcctx=expr.expr.context)
+        res = casts.compile_cast(
+            ir_expr,
+            target_stype,
+            cardinality_mod=expr.cardinality_mod,
+            ctx=subctx,
+            srcctx=expr.expr.context,
+        )
+
     return stmt.maybe_add_view(res, ctx=ctx)
 
 


Test patch:
diff --git a/tests/test_edgeql_select.py b/tests/test_edgeql_select.py
--- a/tests/test_edgeql_select.py
+++ b/tests/test_edgeql_select.py
@@ -6531,6 +6531,16 @@ async def test_edgeql_select_json_01(self):
             [True],
         )
 
+    async def test_edgeql_select_json_02(self):
+        # See issue #4705
+        [json_res] = await self.con._fetchall(
+            r'''
+            SELECT <json>array_agg(Issue)
+            ''',
+            __typenames__=True,
+        )
+        self.assertNotIn('__tname__', json_res)
+
     async def test_edgeql_select_bad_reference_01(self):
         with self.assertRaisesRegex(
                 edgedb.QueryError,