Repository: edgedb/edgedb

Issue:
Migration to remove property is failing when properties have constraints
I have created a database with below migration applied.

```
start migration to { 
    module default { 
        Type Branch{ 
          property branchName: std::str { 
            constraint min_len_value(0);
            constraint max_len_value(255);
          };
          property branchCode: std::int64;
          property branchURL: std::str { 
            constraint max_len_value(500);
            constraint regexp(r"^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~|!:,.;][-a-zA-Z0-9+&@#/%=~_|]");
            constraint min_len_value(5);
          };
        };
    };
};
populate migration ;
commit migration ;
```

Then I wanted to remove "branchURL" and add some new properties. I applied below migration.

```
start migration to { 
    module default { 
        Type Branch{ 
          property branchName: std::str { 
            constraint min_len_value(0);
            constraint max_len_value(255);
          };
          property branchCode: std::int64;
          property phoneNumber: std::str { 
            constraint min_len_value(5);
            constraint max_len_value(50);
            constraint regexp(r"^(+\d{1,2}\s)?(?\d{3})?[\s.-]\d{3}[\s.-]\d{4}$");
          };
          property email: std::str { 
            constraint min_len_value(5);
            constraint max_len_value(50);
            constraint regexp(r"^[a-zA-Z0-9.!#$%&'+=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:.[a-zA-Z0-9-]+)*$");
          };
        };
    };
};
populate migration ;
commit migration ;
```

This migration gives the error :  `edgedb.InvalidReferenceError: property 'branchURL' does not exist`


If I remove the constraints, the migration works.

Migrating from
```
start migration to { 
    module default { 
        Type Branch{ 
          property branchName: std::str;
          property branchCode: std::int64;
          property branchURL: std::str;
        };
    };
};
populate migration ;
commit migration ;
```

to

```
start migration to { 
    module default { 
        Type Branch{ 
          property branchName: std::str;
          property branchCode: std::int64;
          property phoneNumber: std::str;
          property email: std::str;
        };
    };
};
populate migration ;
commit migration ;
```


Discussion:

Resolving patch:
diff --git a/edb/schema/delta.py b/edb/schema/delta.py
--- a/edb/schema/delta.py
+++ b/edb/schema/delta.py
@@ -2316,8 +2316,15 @@ def _get_ast(
         astnode = self._get_ast_node(schema, context)
 
         if astnode.get_field('name'):
-            name = sn.shortname_from_fullname(self.classname)
-            name = context.early_renames.get(name, name)
+            # We need to be able to catch both renames of the object
+            # itself, which might have a long name (for pointers, for
+            # example) as well as an object being referenced by
+            # shortname, if this is (for example) a concrete
+            # constraint and the abstract constraint was renamed.
+            name = context.early_renames.get(self.classname, self.classname)
+            name = sn.shortname_from_fullname(name)
+            if self.classname not in context.early_renames:
+                name = context.early_renames.get(name, name)
             op = astnode(  # type: ignore
                 name=self._deparse_name(schema, context, name),
             )
diff --git a/edb/schema/migrations.py b/edb/schema/migrations.py
--- a/edb/schema/migrations.py
+++ b/edb/schema/migrations.py
@@ -200,6 +200,23 @@ def _cmd_tree_from_ast(
 
         return cmd
 
+    def apply_subcommands(
+        self,
+        schema: s_schema.Schema,
+        context: sd.CommandContext,
+    ) -> s_schema.Schema:
+        assert not self.get_prerequisites() and not self.get_caused()
+        # Renames shouldn't persist between commands in a migration script.
+        context.renames.clear()
+        for op in self.get_subcommands(
+            include_prerequisites=False,
+            include_caused=False,
+        ):
+            if not isinstance(op, sd.AlterObjectProperty):
+                schema = op.apply(schema, context=context)
+                context.renames.clear()
+        return schema
+
     def _get_ast(
         self,
         schema: s_schema.Schema,


Test patch:
diff --git a/tests/test_edgeql_ddl.py b/tests/test_edgeql_ddl.py
--- a/tests/test_edgeql_ddl.py
+++ b/tests/test_edgeql_ddl.py
@@ -13085,6 +13085,25 @@ async def test_edgeql_ddl_create_migration_04(self):
         #     ['test'],
         # )
 
+    async def test_edgeql_ddl_create_migration_05(self):
+        await self.con.execute('''
+            create type X { create property x -> str; };
+        ''')
+        async with self.assertRaisesRegexTx(
+                edgedb.InvalidReferenceError,
+                "property 'x' does not"):
+            await self.con.execute('''
+                CREATE MIGRATION
+                {
+                    alter type default::X {
+                        alter property x rename to y;
+                    };
+                    alter type default::X {
+                        alter property x create constraint exclusive;
+                    };
+                };
+            ''')
+
     async def test_edgeql_ddl_naked_backlink_in_computable(self):
         await self.con.execute('''
             CREATE TYPE User {
diff --git a/tests/test_schema.py b/tests/test_schema.py
--- a/tests/test_schema.py
+++ b/tests/test_schema.py
@@ -8190,6 +8190,118 @@ def test_schema_migrations_rename_with_stuff_04(self):
             """
         ])
 
+    def test_schema_migrations_rename_and_modify_01(self):
+        self._assert_migration_equivalence([
+            r"""
+                type Branch{
+                  property branchURL: std::str {
+                    constraint max_len_value(500);
+                    constraint min_len_value(5);
+                  };
+                };
+            """,
+            r"""
+                type Branch{
+                  property email: std::str {
+                    constraint max_len_value(50);
+                    constraint min_len_value(5);
+                  };
+                };
+            """
+        ])
+
+    def test_schema_migrations_rename_and_modify_02(self):
+        self._assert_migration_equivalence([
+            r"""
+                type X {
+                    obj: Object {
+                        foo: str;
+                    };
+                };
+            """,
+            r"""
+                type X {
+                    obj2: Object {
+                        bar: int64;
+                    };
+                };
+            """
+        ])
+
+    def test_schema_migrations_rename_and_modify_03(self):
+        self._assert_migration_equivalence([
+            r"""
+                type Branch{
+                  property branchName: std::str {
+                    constraint min_len_value(0);
+                    constraint max_len_value(255);
+                  };
+                  property branchCode: std::int64;
+                  property branchURL: std::str {
+                    constraint max_len_value(500);
+                    constraint regexp("url");
+                    constraint min_len_value(5);
+                  };
+                };
+            """,
+            r"""
+                type Branch{
+                  property branchName: std::str {
+                    constraint min_len_value(0);
+                    constraint max_len_value(255);
+                  };
+                  property branchCode: std::int64;
+                  property phoneNumber: std::str {
+                    constraint min_len_value(5);
+                    constraint max_len_value(50);
+                    constraint regexp(r"phone");
+                  };
+                  property email: std::str {
+                    constraint min_len_value(5);
+                    constraint max_len_value(50);
+                    constraint regexp(r"email");
+                  };
+                };
+            """
+        ])
+
+    def test_schema_migrations_rename_and_modify_04(self):
+        self._assert_migration_equivalence([
+            r"""
+                type Branch{
+                  property branchName: std::str {
+                    constraint min_len_value(0);
+                    constraint max_len_value(255);
+                  };
+                  property branchCode: std::int64;
+                  property branchURL: std::str {
+                    constraint max_len_value(500);
+                    constraint regexp("url");
+                    constraint min_len_value(5);
+                  };
+                };
+            """,
+            r"""
+                type Branch2 {
+                  property branchName: std::str {
+                    constraint min_len_value(0);
+                    constraint max_len_value(255);
+                  };
+                  property branchCode: std::int64;
+                  property phoneNumber: std::str {
+                    constraint min_len_value(5);
+                    constraint max_len_value(50);
+                    constraint regexp(r"phone");
+                  };
+                  property email: std::str {
+                    constraint min_len_value(5);
+                    constraint max_len_value(50);
+                    constraint regexp(r"email");
+                  };
+                };
+            """
+        ])
+
     def test_schema_migrations_except_01(self):
         self._assert_migration_equivalence([
             r"""