From 6b2e287def7a26c983949f1b7a16a9107928f7fc Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Tue, 16 Jan 2024 16:51:48 -0800 Subject: [PATCH] Fix spurious delete/create of constraints with arguments in migrations The bug here was that `@index` was not populated in the `params` link for concrete constraints by the reflection writer, and so when we reloaded the schema from the database, it came back in an arbitrary order. This bug has been present for a *long* time, as far as I can tell, but we tended to get "lucky" with the order pg returned the params. This is a strictly *forward* fix. It can be cherry-picked but it will only fix things for constraints created once the fix is applied. I'm working on a backward fix as well. Fixes #6699. --- edb/schema/reflection/writer.py | 7 ++++--- tests/test_edgeql_ddl.py | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/edb/schema/reflection/writer.py b/edb/schema/reflection/writer.py index 30c3e83f5f0..fb80509ddde 100644 --- a/edb/schema/reflection/writer.py +++ b/edb/schema/reflection/writer.py @@ -299,12 +299,13 @@ def _build_object_mutation_shape( # an ObjectKeyDict collection that allow associating objects # with arbitrary values (a transposed ObjectDict). target_expr = f"""assert_distinct(( - FOR v IN {{ json_array_unpack(${var_n}) }} + FOR v IN {{ enumerate(json_array_unpack(${var_n})) }} UNION ( SELECT {target.get_name(schema)} {{ - @value := v[1] + @index := v.0, + @value := v.1[1], }} - FILTER .id = v[0] + FILTER .id = v.1[0] ) ))""" args = props.get('args', []) diff --git a/tests/test_edgeql_ddl.py b/tests/test_edgeql_ddl.py index 0e2577e95ae..cfd740616b5 100644 --- a/tests/test_edgeql_ddl.py +++ b/tests/test_edgeql_ddl.py @@ -10190,6 +10190,26 @@ async def test_edgeql_ddl_constraint_09(self): CREATE TYPE Comment EXTENDING Text; """) + await self.assert_query_result( + """ + select schema::Constraint { + name, params: {name, @index} order by @index + } + filter .name = 'std::max_len_value' + and .subject.name = 'body' + and .subject[is schema::Pointer].source.name ='default::Text'; + """, + [ + { + "name": "std::max_len_value", + "params": [ + {"name": "__subject__", "@index": 0}, + {"name": "max", "@index": 1} + ] + } + ], + ) + await self.con.execute(""" ALTER TYPE Text ALTER PROPERTY body