From 637f15ceda0644e5feb037a00b5cf410eb02d322 Mon Sep 17 00:00:00 2001 From: dnwpark Date: Mon, 24 Feb 2025 13:26:27 -0500 Subject: [PATCH] Add hint to partial path errors if anchor is available. --- edb/edgeql/compiler/setgen.py | 28 +++++++++++++++++++++++++++- tests/test_edgeql_expressions.py | 5 ++++- tests/test_edgeql_insert.py | 1 + tests/test_edgeql_select.py | 12 ++++++++---- tests/test_schema.py | 22 ++++++++++++++++++++-- 5 files changed, 60 insertions(+), 8 deletions(-) diff --git a/edb/edgeql/compiler/setgen.py b/edb/edgeql/compiler/setgen.py index edd61477f54..144a1f51413 100644 --- a/edb/edgeql/compiler/setgen.py +++ b/edb/edgeql/compiler/setgen.py @@ -319,9 +319,35 @@ def compile_path(expr: qlast.Path, *, ctx: context.ContextLevel) -> irast.Set: if ctx.partial_path_prefix is not None: path_tip = ctx.partial_path_prefix else: + hint = None + + # If there are anchors, suggest one + if anchors: + anchor_names: list[str] = [ + key if isinstance(key, str) else key.name + for key in anchors + ] + + import edb.edgeql.codegen + suggestion = ( + f'{anchor_names[0]}' + f'{edb.edgeql.codegen.generate_source(expr)}' + ) + + if len(anchor_names) == 1: + hint = ( + f'Did you mean {suggestion}?' + ) + else: + hint = ( + f'Did you mean to use one of: {anchor_names}? ' + f'eg. {suggestion}' + ) + raise errors.QueryError( 'could not resolve partial path ', - span=expr.span + span=expr.span, + hint=hint ) computables: list[irast.Set] = [] diff --git a/tests/test_edgeql_expressions.py b/tests/test_edgeql_expressions.py index 0d11ab3b5ac..5b5a2c616af 100644 --- a/tests/test_edgeql_expressions.py +++ b/tests/test_edgeql_expressions.py @@ -2609,7 +2609,10 @@ async def test_edgeql_expr_paths_03(self): # syntactically legal (see test_edgeql_syntax_constants_09), # but will fail to resolve to anything. with self.assertRaisesRegex( - edgedb.QueryError, r'could not resolve partial path'): + edgedb.QueryError, + r'could not resolve partial path', + _hint=None + ): await self.con.execute(r""" SELECT .1; """) diff --git a/tests/test_edgeql_insert.py b/tests/test_edgeql_insert.py index e3da3907084..37cabe9adf5 100644 --- a/tests/test_edgeql_insert.py +++ b/tests/test_edgeql_insert.py @@ -103,6 +103,7 @@ async def test_edgeql_insert_fail_06(self): with self.assertRaisesRegex( edgedb.QueryError, r"could not resolve partial path", + _hint=None ): await self.con.execute(''' INSERT Person { name := .name }; diff --git a/tests/test_edgeql_select.py b/tests/test_edgeql_select.py index 94fd98cf150..d9921f7aba4 100644 --- a/tests/test_edgeql_select.py +++ b/tests/test_edgeql_select.py @@ -1292,8 +1292,10 @@ async def test_edgeql_select_limit_07(self): async def test_edgeql_select_limit_08(self): with self.assertRaisesRegex( - edgedb.QueryError, - r'could not resolve partial path'): + edgedb.QueryError, + r'could not resolve partial path', + _hint=None + ): await self.con.query(""" SELECT @@ -1303,8 +1305,10 @@ async def test_edgeql_select_limit_08(self): async def test_edgeql_select_limit_09(self): with self.assertRaisesRegex( - edgedb.QueryError, - r'could not resolve partial path'): + edgedb.QueryError, + r'could not resolve partial path', + _hint=None + ): await self.con.query(""" SELECT diff --git a/tests/test_schema.py b/tests/test_schema.py index 663cf44c221..a4a9174be29 100644 --- a/tests/test_schema.py +++ b/tests/test_schema.py @@ -455,8 +455,11 @@ def test_schema_deletion_policy_on_prop_02(self): }; """ - @tb.must_fail(errors.QueryError, - "could not resolve partial path") + @tb.must_fail( + errors.QueryError, + "could not resolve partial path", + hint="Did you mean __source__.name?" + ) def test_schema_partial_path_in_default_of_link_prop_01(self): """ module default { @@ -475,6 +478,21 @@ def test_schema_partial_path_in_default_of_link_prop_01(self): } """ + @tb.must_fail( + errors.QueryError, + "could not resolve partial path", + hint="Did you mean __new__.wow?" + ) + def test_schema_partial_path_in_trigger_01(self): + """ + type Foo { + property wow: bool; + trigger prohibit_queue after insert for each do ( + select assert(.wow, message := "wow!") + ); + } + """ + @tb.must_fail(errors.InvalidPropertyTargetError, "invalid property type: expected a scalar type, " "or a scalar collection, got object type 'test::Object'",