Repository: edgedb/edgedb

Issue:
Group by - ProtocolError: cannot decode Object: expected 3 elements, got 2110812590
Hi

```
# this is working
group EntryItem
by .account;

# this is not working
group EntryItem
using accountCode := .account
by accountCode;
-> ProtocolError: cannot decode Object: expected 3 elements, got 2110812590
```

- EdgeDB Version: 2.9
- EdgeDB CLI Version: 2.2.6+7eabbf9
- OS Version: macOS 12.1

Schema:

```
module default {
    type Account {
        required link book -> Book;
        required property code -> str {
            constraint exclusive;
        };

        property displayCode := .code[0:5] ++ ' ' ++ .code[5:];
        required property name -> str;
        required link currency -> Currency;

        constraint exclusive on ((.book, .code));
    }

    type EntryItem {
        required link entry -> Entry;
        required property lineNumber -> int16;

        required link account -> Account;
        ...

        constraint exclusive on ((.entry, .lineNumber))
    }
}
```



Discussion:
I'm having trouble reproducing this. What is the version of this instance? (You can find it with `edgedb instance list`.)
local  │ boki        │ 10706             │ 2.9+a3d80ef │ running
Would you try upgrading your project and see if that helps? 
```bash
edgedb project upgrade --to-latest
```
Same result

```
❯ edgedb project upgrade --to-latest
Fetching https://packages.edgedb.com/archive/.jsonindexes/x86_64-apple-darwin.json takes too long. Common reasons are:
  1. Your internet connectivity is slow
  2. Firewall blocks internet access to this resource
Fetching https://packages.edgedb.com/archive/.jsonindexes/x86_64-apple-darwin.json takes too long. Common reasons are:
  1. Your internet connectivity is slow
  2. Firewall blocks internet access to this resource
Latest version found 2.9+a3d80ef, current instance version is 2.9+a3d80ef. Already up to date.
```


I can reproduce this with the module
```
module default {
    type Account {
        required property code -> str {
            constraint exclusive;
        };
    }

    type EntryItem {
        required property lineNumber -> int16;
        required link account -> Account;
    }
}
```
and data populated by
```
insert EntryItem { lineNumber := 1, account := (insert Account {code := "1"} ) };
```

The issue is that we seem to be returning just the `id` for `accountCode` in the `key` field of the object, rather than a shape containing the `id`. This is visible in the json output:
```
[
  {
    "elements": [{"id": "12d67453-9765-11ed-9af2-bbf010205dec"}],
    "grouping": ["accountCode"],
    "key": {"accountCode": "12d67452-9765-11ed-9af2-57c612b85eb5"}
  }
]
```
Here, the `accountCode` ought to be `{"id": "12d67452-9765-11ed-9af2-57c612b85eb5"}`

Resolving patch:
diff --git a/edb/edgeql/desugar_group.py b/edb/edgeql/desugar_group.py
--- a/edb/edgeql/desugar_group.py
+++ b/edb/edgeql/desugar_group.py
@@ -27,6 +27,8 @@
 
 from typing import Optional, Tuple, AbstractSet, Dict, List
 
+from edb import errors
+
 from edb.common import ast
 from edb.common import ordered
 from edb.common.compiler import AliasGenerator
@@ -126,11 +128,22 @@ def rewrite(el: qlast.GroupingElement) -> qlast.GroupingElement:
                 elements=[rewrite_atom(a) for a in el.elements])
         raise AssertionError
 
+    # The rewrite calls on the grouping elements populate alias_map
+    # with any bindings for pointers the by clause refers to directly.
+    by = [rewrite(by_el) for by_el in node.by]
+
     for using_clause in (node.using or ()):
+        if using_clause.alias in alias_map:
+            # TODO: This would be a great place to allow multiple spans!
+            raise errors.QueryError(
+                f"USING clause binds a variable '{using_clause.alias}' "
+                f"but a property with that name is used directly in the BY "
+                f"clause",
+                span=alias_map[using_clause.alias][1].span,
+            )
         alias_map[using_clause.alias] = (using_clause.alias, using_clause.expr)
 
-    using = node.using[:] if node.using else []
-    by = [rewrite(by_el) for by_el in node.by]
+    using = []
     for alias, path in alias_map.values():
         using.append(qlast.AliasedExpr(alias=alias, expr=path))
 


Test patch:
diff --git a/tests/test_edgeql_group.py b/tests/test_edgeql_group.py
--- a/tests/test_edgeql_group.py
+++ b/tests/test_edgeql_group.py
@@ -510,6 +510,17 @@ async def test_edgeql_group_grouping_sets_02(self):
             ]
         )
 
+    async def test_edgeql_group_duplicate_rejected(self):
+        async with self.assertRaisesRegexTx(
+            edgedb.QueryError,
+            "used directly in the BY clause",
+        ):
+            await self.con.execute('''
+                group Card { name }
+                using element := .cost
+                by cube(.element, element)
+            ''')
+
     async def test_edgeql_group_for_01(self):
         await self.assert_query_result(
             r'''
@@ -1568,12 +1579,6 @@ async def test_edgeql_group_issue_5757(self):
             always_typenames=True,
         )
 
-    @test.xfail("""
-        Issue #4897
-
-        The link isn't having a view put on it, it's going out raw as
-        just a uuid.
-    """)
     async def test_edgeql_group_issue_4897(self):
         await self.assert_query_result(
             '''