Repository: edgedb/edgedb

Issue:
Nested upsert not working as expected 
I'm having some trouble understanding why a nested upsert is failing in some circumstances. From reading some recent issues / PRs on `UNLESS CONFLICT ON` it appears as though this _should_ work. I'm unsure if this related to https://github.com/edgedb/edgedb/issues/2542

<!-- Please search existing issues to avoid creating duplicates. -->
- EdgeDB Version: 1.0b2+ga7130d5c7.cv202104290000
- OS Version: macOS Big Sur (11.3.1)

Steps to Reproduce:

1. Create db with schema below
2. Execute the following upsert, which returns `{}` (as opposed to the expected inserted uuid) 
```
SELECT (
  INSERT InstrumentId {
    value := "instrument",
    symbol := (
      INSERT Symbol {value := "symbol", } 
      UNLESS CONFLICT ON Symbol.value ELSE (SELECT Symbol)
    ),
    venue := (
      INSERT Venue {value := "venue"} 
      UNLESS CONFLICT ON Venue.value ELSE (SELECT Venue)
    ),
  }
  UNLESS CONFLICT ON InstrumentId.value ELSE (SELECT InstrumentId)
); 
```
Some notes: 
- On a fresh instances it seems to insert the `symbol`, but fail on the `venue` (for reasons unclear to me), exiting out.
- If I start fresh, insert the `venue` first and run the above, it works as expected. 
- It also works if I move the nested upserts into variables under a WITH statement at thee top of the query. 
- I've used the fully qualified names everything to ensure I wasn't get confused about scopes etc.

Could anyone shed some light on why this particular case fails? I could always pull my nested upserts out, but I have more complex objects than this, and I would like to just be able to generate nested queries if possible (avoiding some toposort of required variables under a WITH statement. 

<!-- If the issue is about a query error, please also provide your schema -->
Schema:
```
module default {
    abstract type Identifer {
        required property value -> str;
        constraint exclusive on ( .value );
    }

    type Symbol extending Identifer {}
    type Venue extending Identifer {}

    type InstrumentId extending Identifer {
        link symbol -> Symbol; 
        link venue -> Venue;
    }
}
```



Discussion:
Yeah, definitely a bug!

Resolving patch:
diff --git a/edb/pgsql/compiler/dml.py b/edb/pgsql/compiler/dml.py
--- a/edb/pgsql/compiler/dml.py
+++ b/edb/pgsql/compiler/dml.py
@@ -34,10 +34,11 @@
 
 from typing import *
 
+from edb.common import uuidgen
+
 from edb.edgeql import ast as qlast
 from edb.edgeql import qltypes
 
-from edb.schema import objects as s_obj
 from edb.schema import name as sn
 
 from edb.ir import ast as irast
@@ -845,7 +846,7 @@ def compile_insert_else_body(
             # that *aren't* being filtered out
             dummy_pathid = irast.PathId.from_typeref(
                 typeref=irast.TypeRef(
-                    id=s_obj.get_known_type_id('std::uuid'),
+                    id=uuidgen.uuid1mc(),
                     name_hint=sn.QualName(
                         module='__derived__',
                         name=ctx.env.aliases.get('dummy'))))


Test patch:
diff --git a/tests/test_edgeql_insert.py b/tests/test_edgeql_insert.py
--- a/tests/test_edgeql_insert.py
+++ b/tests/test_edgeql_insert.py
@@ -3689,6 +3689,48 @@ async def test_edgeql_insert_dependent_26(self):
             [2],
         )
 
+    async def test_edgeql_insert_dependent_27(self):
+        # test with two nested single links
+        await self.con.execute('''
+            SET MODULE test;
+            CREATE ABSTRACT TYPE Named {
+                CREATE REQUIRED PROPERTY name -> str {
+                    CREATE DELEGATED CONSTRAINT exclusive;
+                };
+            };
+
+            CREATE TYPE Foo EXTENDING Named;
+            CREATE TYPE Bar EXTENDING Named;
+
+            CREATE TYPE Obj extending Named {
+                CREATE LINK foo -> Foo;
+                CREATE LINK bar -> Bar;
+            };
+        ''')
+
+        await self.assert_query_result(
+            r'''
+                INSERT Obj {
+                    name := "obj",
+                    foo := (
+                        INSERT Foo {name := "foo"}
+                        UNLESS CONFLICT ON .name ELSE (SELECT Foo)
+                    ),
+                    bar := (
+                        INSERT Bar {name := "bar"}
+                        UNLESS CONFLICT ON .name ELSE (SELECT Bar)
+                    ),
+                }
+                UNLESS CONFLICT ON .name ELSE (SELECT Obj);
+            ''',
+            [{"id": {}}]
+        )
+
+        await self.assert_query_result(
+            "SELECT test::Obj {name, foo: {name}, bar: {name}}",
+            [{"name": "obj", "foo": {"name": "foo"}, "bar": {"name": "bar"}}],
+        )
+
     async def test_edgeql_insert_unless_conflict_self_01(self):
         # It would also be a reasonable semantics for this test to
         # return two objects