Repository: edgedb/edgedb

Issue:
Abstract type property rewrite not honored?
- EdgeDB Version: 3.0-dev.7436+5e52253
- EdgeDB CLI Version: EdgeDB CLI 3.0.0-dev.968+d9d8ac3
- OS Version: Linux vd 5.4.0-137-generic #154-Ubuntu SMP Thu Jan 5 17:03:22 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

Steps to Reproduce:

1. The following schema:
```
  abstract type Resource {
    required property name: str {
      rewrite insert, update using (str_trim(.name));
    }
  }

  type Project extending Resource {
    # overloaded required property name: str {
    #   rewrite insert, update using (str_trim(.name));
    # }
  }
```
3. `update Project set { name := " a " }` does not change the name property.
4. Changed the schema:
```
  abstract type Resource {
    required property name: str {}
  }

  type Project extending Resource {
    overloaded required property name: str {
      rewrite insert, update using (str_trim(.name));
    }
  }
```
5. `update Project set { name := " a " }` works fine.

Am I doing rewrite rules wrong or this is intended?
TIA



Discussion:

Resolving patch:
diff --git a/edb/edgeql/compiler/viewgen.py b/edb/edgeql/compiler/viewgen.py
--- a/edb/edgeql/compiler/viewgen.py
+++ b/edb/edgeql/compiler/viewgen.py
@@ -1004,8 +1004,13 @@ def _compile_rewrites_for_stype(
             continue
         rewrite_pointer = downcast(
             s_pointers.Pointer, rewrite.get_subject(schema))
-        rewrite_source = downcast(
-            s_objtypes.ObjectType, rewrite_pointer.get_source(schema))
+
+        # Because rewrites are not duplicated on inherited properties, the
+        # subject this pointer will not be on stype, but on one of its
+        # ancestors. Mitigation is to pick the correct pointer from the stype.
+        rewrite_pointer = downcast(
+            s_pointers.Pointer, stype.get_pointers(schema).get(schema, pn)
+        )
 
         # get_rewrite searches in ancestors for rewrites, but if the rewrite
         # for that ancestor has already been compiled, skip it to avoid
@@ -1021,12 +1026,12 @@ def _compile_rewrites_for_stype(
         subject_set, specified_set, old_set = anchors
 
         rewrite_view = view_scls
-        if rewrite_source != view_scls.get_nearest_non_derived_parent(schema):
+        if stype != view_scls.get_nearest_non_derived_parent(schema):
             # FIXME: Caching?
             rewrite_view = downcast(
                 s_objtypes.ObjectType,
                 schemactx.derive_view(
-                    rewrite_source,
+                    stype,
                     exprtype=s_ctx.exprtype,
                     ctx=ctx,
                 )


Test patch:
diff --git a/tests/test_edgeql_rewrites.py b/tests/test_edgeql_rewrites.py
--- a/tests/test_edgeql_rewrites.py
+++ b/tests/test_edgeql_rewrites.py
@@ -29,7 +29,8 @@ class TestRewrites(tb.QueryTestCase):
     SCHEMA = os.path.join(os.path.dirname(__file__), 'schemas', 'movies.esdl')
     # Setting up some rewrites makes the tests run a bit faster
     # because we don't need to recompile the delta scripts for it.
-    SETUP = ["""
+    SETUP = [
+        """
         create type Asdf {
           create property title -> str {
             create rewrite update using ('updated');
@@ -40,7 +41,16 @@ class TestRewrites(tb.QueryTestCase):
             create rewrite insert using ('inserted');
           };
         };
-    """]
+
+        create abstract type Resource {
+          create required property name: str {
+            create rewrite insert, update using (str_trim(.name));
+          };
+        };
+
+        create type Project extending Resource;
+    """
+    ]
 
     # TO TEST:
     # * Trigger interactions
@@ -843,3 +853,76 @@ async def test_edgeql_rewrites_21(self):
                 INSERT Conflicted { a := 'hello' }
                 UNLESS CONFLICT
             ''')
+
+    async def test_edgeql_rewrites_22(self):
+        await self.con.execute(
+            '''
+            insert Project { name := ' hello ' };
+            '''
+        )
+        await self.assert_query_result(
+            '''
+                select Project { name }
+            ''',
+            [
+                {'name': 'hello'},
+            ],
+        )
+
+        await self.con.execute(
+            '''
+            update Project set { name := ' world ' };
+            '''
+        )
+        await self.assert_query_result(
+            '''
+                select Project { name }
+            ''',
+            [
+                {'name': 'world'},
+            ],
+        )
+
+        await self.con.execute(
+            '''
+            alter type Project {
+                alter property name {
+                    create rewrite insert, update using ('hidden');
+                };
+            };
+            '''
+        )
+
+        await self.con.execute(
+            '''
+            insert Project { name := ' hey ' };
+            '''
+        )
+        await self.assert_query_result(
+            '''
+                select Project { name }
+            ''',
+            tb.bag(
+                [
+                    {'name': 'world'},
+                    {'name': 'hidden'},
+                ]
+            ),
+        )
+
+        await self.con.execute(
+            '''
+            update Project set { name := ' hoy ' };
+            '''
+        )
+        await self.assert_query_result(
+            '''
+                select Project { name }
+            ''',
+            tb.bag(
+                [
+                    {'name': 'hidden'},
+                    {'name': 'hidden'},
+                ]
+            ),
+        )