Repository: edgedb/edgedb

Issue:
Trying to drop a type with `edb migration create` causes a crash
<!-- Please search existing issues to avoid creating duplicates. -->
- EdgeDB Version: `EdgeDB CLI 1.0.0+5724c50`, `1.0+9ecadfc`
- OS Version: Windows 10 running WSL w/ Ubuntu 20.04 😬 

Steps to Reproduce:

1. Initialize a project with the following schema definition:
```
module default {
  type Document {
    multi link entries -> Entry {
      constraint exclusive;
    }
    multi link fields := .entries.field;
    required link form -> Form;
  }

  type Entry {
    required link field -> Field;
    required property value -> str;
    link form := .field.form; 
  }

  type Field {
    required property name -> str;

    link form := .<fields[IS Form];
  }

  type Form {
    required property name -> str {
      constraint exclusive;
    }

    multi link fields -> Field;
  }
}
```
2. `edb migration create; edb migrate;`
3. delete the `Document` type
4. `edb migration create`
5. crash
```
edgedb error: InternalServerError: 
  Hint: This is most likely a bug in EdgeDB. Please consider opening an issue ticket at https://github.com/edgedb/edgedb/issues/new?template=bug_report.md      
  Server traceback:
      Traceback (most recent call last):
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/server/compiler_pool/worker.py", line 309, in worker
          res = meth(*args)
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/server/compiler_pool/worker.py", line 202, in compile_in_tx
          units, cstate = COMPILER.compile_in_tx(cstate, *args, **kwargs)       
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/server/compiler/compiler.py", line 2137, in compile_in_tx
          return self._compile(ctx=ctx, source=source), ctx.state
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/server/compiler/compiler.py", line 1654, in _compile
          return self._try_compile(ctx=ctx, source=original)
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/server/compiler/compiler.py", line 1710, in _try_compile
          comp, capabilities = self._compile_dispatch_ql(
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/server/compiler/compiler.py", line 1593, in _compile_dispatch_ql    
          query = self._compile_ql_migration(ctx, ql)
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/server/compiler/compiler.py", line 1091, in _compile_ql_migration   
          proposed_ddl = s_ddl.statements_from_delta(
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/schema/ddl.py", line 707, in statements_from_delta
          stmts = ddlast_from_delta(
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/schema/ddl.py", line 688, in ddlast_from_delta
          ql_ast = command.get_ast(schema, context)
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/schema/types.py", line 2173, in get_ast
          return super().get_ast(schema, context, parent_node=parent_node)      
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/schema/delta.py", line 2593, in get_ast
          return self._get_ast(schema, context, parent_node=parent_node)        
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/schema/objtypes.py", line 567, in _get_ast
          return super()._get_ast(schema, context, parent_node=parent_node)     
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/schema/types.py", line 779, in _get_ast
          return super()._get_ast(schema, context, parent_node=parent_node)     
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/schema/delta.py", line 2159, in _get_ast
          self._apply_fields_ast(schema, context, op)
        File "/home/ianch/.local/share/edgedb/portable/1.0/lib/python3.10/site-packages/edb/schema/delta.py", line 2240, in _apply_fields_ast
          assert all(
      AssertionError
```



Discussion:
Confirmed.

Resolving patch:
diff --git a/edb/schema/delta.py b/edb/schema/delta.py
--- a/edb/schema/delta.py
+++ b/edb/schema/delta.py
@@ -2233,12 +2233,18 @@ def _apply_fields_ast(
                 self._append_subcmd_ast(schema, node, op, context)
 
         if isinstance(node, qlast.DropObject):
+            def _is_drop(ddl: qlast.DDLOperation) -> bool:
+                return (
+                    isinstance(ddl, (qlast.DropObject, qlast.AlterObject))
+                    and all(_is_drop(sub) for sub in ddl.commands)
+                )
+
             # Deletes in the AST shouldn't have subcommands, so we
             # drop them.  To try to make sure we aren't papering
             # over bugs by dropping things we dont expect, make
-            # sure every subcommand was also a delete.
-            assert all(
-                isinstance(sub, qlast.DropObject) for sub in node.commands)
+            # sure every subcommand was also a delete (or an alter
+            # containing only deletes)
+            assert all(_is_drop(sub) for sub in node.commands)
             node.commands = []
 
     def _apply_field_ast(


Test patch:
diff --git a/tests/test_edgeql_data_migration.py b/tests/test_edgeql_data_migration.py
--- a/tests/test_edgeql_data_migration.py
+++ b/tests/test_edgeql_data_migration.py
@@ -10506,6 +10506,58 @@ async def test_edgeql_migration_drop_constraint_05(self):
             }
         ''')
 
+    async def test_edgeql_migration_fiddly_delete_01(self):
+        await self.migrate(r'''
+            type Document {
+              multi link entries -> Entry {
+                constraint exclusive;
+              }
+              multi link fields := .entries.field;
+              required link form -> Form;
+            }
+
+            type Entry {
+              required link field -> Field;
+              required property value -> str;
+              link form := .field.form;
+            }
+
+            type Field {
+              required property name -> str;
+
+              link form := .<fields[IS Form];
+            }
+
+            type Form {
+              required property name -> str {
+                constraint exclusive;
+              }
+
+              multi link fields -> Field;
+            }
+        ''')
+        await self.migrate(r'''
+            type Entry {
+              required link field -> Field;
+              required property value -> str;
+              link form := .field.form;
+            }
+
+            type Field {
+              required property name -> str;
+
+              link form := .<fields[IS Form];
+            }
+
+            type Form {
+              required property name -> str {
+                constraint exclusive;
+              }
+
+              multi link fields -> Field;
+            }
+        ''')
+
 
 class TestEdgeQLDataMigrationNonisolated(tb.DDLTestCase):
     TRANSACTION_ISOLATION = False