From d957415d1f54fdcd941b112cc51e6affd81842f4 Mon Sep 17 00:00:00 2001 From: Laurence Isla Date: Fri, 9 Dec 2022 21:07:35 -0500 Subject: [PATCH 1/8] Add simple suggestion when no relationship is found --- src/PostgREST/ApiRequest/Types.hs | 4 ++-- src/PostgREST/Error.hs | 36 ++++++++++++++++++++++++---- src/PostgREST/Plan.hs | 2 +- test/spec/Feature/Query/QuerySpec.hs | 4 ++-- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/PostgREST/ApiRequest/Types.hs b/src/PostgREST/ApiRequest/Types.hs index e7985405de..053f621890 100644 --- a/src/PostgREST/ApiRequest/Types.hs +++ b/src/PostgREST/ApiRequest/Types.hs @@ -35,7 +35,7 @@ import PostgREST.MediaType (MediaType (..)) import PostgREST.SchemaCache.Identifiers (FieldName, QualifiedIdentifier) import PostgREST.SchemaCache.Proc (ProcDescription (..)) -import PostgREST.SchemaCache.Relationship (Relationship) +import PostgREST.SchemaCache.Relationship (Relationship, RelationshipsMap) import Protolude @@ -72,7 +72,7 @@ data ApiRequestError | InvalidRpcMethod ByteString | LimitNoOrderError | NotFound - | NoRelBetween Text Text Text + | NoRelBetween Text Text (Maybe Text) Text RelationshipsMap | NoRpc Text Text [Text] Bool MediaType Bool [QualifiedIdentifier] [ProcDescription] | NotEmbedded Text | ParseRequestError Text Text diff --git a/src/PostgREST/Error.hs b/src/PostgREST/Error.hs index 7e45df4837..7a69deae01 100644 --- a/src/PostgREST/Error.hs +++ b/src/PostgREST/Error.hs @@ -18,6 +18,7 @@ module PostgREST.Error import qualified Data.Aeson as JSON import qualified Data.ByteString.Char8 as BS import qualified Data.FuzzySet as Fuzzy +import qualified Data.HashMap.Strict as HM import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.Text.Encoding.Error as T @@ -41,7 +42,8 @@ import PostgREST.SchemaCache.Proc (ProcDescription (..), ProcParam (..)) import PostgREST.SchemaCache.Relationship (Cardinality (..), Junction (..), - Relationship (..)) + Relationship (..), + RelationshipsMap) import Protolude @@ -174,11 +176,11 @@ instance JSON.ToJSON ApiRequestError where "details" .= ("Only is null or not is null filters are allowed on embedded resources":: Text), "hint" .= JSON.Null] - toJSON (NoRelBetween parent child schema) = JSON.object [ + toJSON (NoRelBetween parent child hint schema allRels) = JSON.object [ "code" .= SchemaCacheErrorCode00, "message" .= ("Could not find a relationship between '" <> parent <> "' and '" <> child <> "' in the schema cache" :: Text), - "details" .= JSON.Null, - "hint" .= ("Verify that '" <> parent <> "' and '" <> child <> "' exist in the schema '" <> schema <> "' and that there is a foreign key relationship between them. If a new relationship was created, try reloading the schema cache." :: Text)] + "details" .= ("Searched for a foreign key relationship between '" <> parent <> "' and '" <> child <> maybe "" ("' using the hint '" <>) hint <> "' in the schema '" <> schema <> "', but no matches were found."), + "hint" .= noRelBetweenHint parent child schema allRels] toJSON (AmbiguousRelBetween parent child rels) = JSON.object [ "code" .= SchemaCacheErrorCode01, @@ -214,6 +216,32 @@ instance JSON.ToJSON ApiRequestError where "details" .= JSON.Null, "hint" .= ("Try renaming the parameters or the function itself in the database so function overloading can be resolved" :: Text)] +noRelBetweenHint :: Text -> Text -> Text -> RelationshipsMap -> Maybe Text +noRelBetweenHint parent child schema allRels = ("Perhaps you meant '" <>) <$> + if isJust (findMatch parent) + then (<> "' instead of '" <> child <> "'.") <$> suggestChild + else (<> "' instead of '" <> parent <> "'.") <$> suggestParent + where + findMatch val = HM.lookup (QualifiedIdentifier schema val, schema) allRels + fuzzySetOfParents = Fuzzy.fromList [qiName (fst p) | p <- HM.keys allRels, snd p == schema] + fuzzySetOfChildren = Fuzzy.fromList [qiName (relForeignTable c) | c <- fromMaybe [] (findMatch parent)] + suggestParent = Fuzzy.getOne fuzzySetOfParents parent + -- Do not suggest if the child is found in the relations (weight = 1.0) + suggestChild = headMay [snd k | k <- Fuzzy.get fuzzySetOfChildren child, fst k < 1.0] +-- TODO: Maybe more complex suggestions are needed? E.g. both parent and child not found +--noRelBetweenHint parent child schema allRels = +-- ("Perhaps you meant to select a relationship between '" <>) +-- (<> ("instead of '" <> parent <> "' and '" <> child <> "'")) <$> +-- case findMatch parent of +-- Just rels -> ((parent <> "' and '") <>) <$> suggestChild rels +-- _ -> findMatch +-- where +-- findMatch val = HM.lookup (QualifiedIdentifier schema val, schema) allRels +-- fuzzySetOfParents = Fuzzy.fromList [qiName (fst p) | p <- rels, snd p == schema] +-- fuzzySetOfChildren rels = Fuzzy.fromList [qiName (relForeignTable c) | c <- fromMaybe [] (findMatch parent)] +-- suggestParent = Fuzzy.getOne fuzzySetOfParents parent +-- suggestChild rels = Fuzzy.getOne (fuzzySetOfChildren rels) child + -- | -- If no function is found with the given name, it does a fuzzy search to all the functions -- in the same schema and shows the best match as hint. diff --git a/src/PostgREST/Plan.hs b/src/PostgREST/Plan.hs index 3d5b425964..ff30b915d0 100644 --- a/src/PostgREST/Plan.hs +++ b/src/PostgREST/Plan.hs @@ -208,7 +208,7 @@ getJoinConditions tblAlias parentAlias Relationship{relTable=qi,relForeignTable= findRel :: Schema -> RelationshipsMap -> NodeName -> NodeName -> Maybe Hint -> Either ApiRequestError Relationship findRel schema allRels origin target hint = case rels of - [] -> Left $ NoRelBetween origin target schema + [] -> Left $ NoRelBetween origin target hint schema allRels [r] -> Right r rs -> Left $ AmbiguousRelBetween origin target rs where diff --git a/test/spec/Feature/Query/QuerySpec.hs b/test/spec/Feature/Query/QuerySpec.hs index eedf0d703b..8e2340f70f 100644 --- a/test/spec/Feature/Query/QuerySpec.hs +++ b/test/spec/Feature/Query/QuerySpec.hs @@ -590,8 +590,8 @@ spec actualPgVersion = do it "cannot request partitions as children from a partitioned table" $ get "/car_models?id=in.(1,2,4)&select=id,name,car_model_sales_202101(id)&order=id.asc" `shouldRespondWith` [json| - {"hint":"Verify that 'car_models' and 'car_model_sales_202101' exist in the schema 'test' and that there is a foreign key relationship between them. If a new relationship was created, try reloading the schema cache.", - "details":null, + {"hint":"Perhaps you meant 'car_model_sales' instead of 'car_model_sales_202101'.", + "details":"Searched for a foreign key relationship between 'car_models' and 'car_model_sales_202101' in the schema 'test', but no matches were found.", "code":"PGRST200", "message":"Could not find a relationship between 'car_models' and 'car_model_sales_202101' in the schema cache"} |] { matchStatus = 400 From d0e2ba717ffe797679c3a6a69c830a6b9aa7a3ec Mon Sep 17 00:00:00 2001 From: Laurence Isla Date: Mon, 12 Dec 2022 18:00:51 -0500 Subject: [PATCH 2/8] Add doctests and clean code --- src/PostgREST/Error.hs | 57 ++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/PostgREST/Error.hs b/src/PostgREST/Error.hs index 7a69deae01..e5abbc311d 100644 --- a/src/PostgREST/Error.hs +++ b/src/PostgREST/Error.hs @@ -176,10 +176,10 @@ instance JSON.ToJSON ApiRequestError where "details" .= ("Only is null or not is null filters are allowed on embedded resources":: Text), "hint" .= JSON.Null] - toJSON (NoRelBetween parent child hint schema allRels) = JSON.object [ + toJSON (NoRelBetween parent child embedHint schema allRels) = JSON.object [ "code" .= SchemaCacheErrorCode00, "message" .= ("Could not find a relationship between '" <> parent <> "' and '" <> child <> "' in the schema cache" :: Text), - "details" .= ("Searched for a foreign key relationship between '" <> parent <> "' and '" <> child <> maybe "" ("' using the hint '" <>) hint <> "' in the schema '" <> schema <> "', but no matches were found."), + "details" .= ("Searched for a foreign key relationship between '" <> parent <> "' and '" <> child <> maybe mempty ("' using the hint '" <>) embedHint <> "' in the schema '" <> schema <> "', but no matches were found."), "hint" .= noRelBetweenHint parent child schema allRels] toJSON (AmbiguousRelBetween parent child rels) = JSON.object [ @@ -216,31 +216,50 @@ instance JSON.ToJSON ApiRequestError where "details" .= JSON.Null, "hint" .= ("Try renaming the parameters or the function itself in the database so function overloading can be resolved" :: Text)] +-- | +-- If no relationship is found between a parent and a child, then it looks for the parent first. +-- If the parent is not found then it does a fuzzy search to all the parents in the schema cache and +-- gives the best match as suggestion. Otherwise, it does a fuzzy search to all the corresponding children +-- of that parent and gives the best match as suggestion. If both are found, then no suggestion is given. +-- +-- >>> :set -Wno-missing-fields +-- >>> let qi t = QualifiedIdentifier "api" t +-- >>> let rel ft = Relationship{relForeignTable = qi ft} +-- >>> let rels = HM.fromList [((qi "films", "api"), [rel "directors", rel "roles", rel "actors"])] +-- +-- >>> noRelBetweenHint "film" "directors" "api" rels +-- Just "Perhaps you meant 'films' instead of 'film'." +-- +-- >>> noRelBetweenHint "films" "role" "api" rels +-- Just "Perhaps you meant 'roles' instead of 'role'." +-- +-- >>> noRelBetweenHint "films" "role" "api" rels +-- Just "Perhaps you meant 'roles' instead of 'role'." +-- +-- >>> noRelBetweenHint "films" "actors" "api" rels +-- Nothing +-- +-- >>> noRelBetweenHint "noclosealternative" "roles" "api" rels +-- Nothing +-- +-- >>> noRelBetweenHint "films" "noclosealternative" "api" rels +-- Nothing +-- +-- >>> noRelBetweenHint "films" "noclosealternative" "noclosealternative" rels +-- Nothing +-- noRelBetweenHint :: Text -> Text -> Text -> RelationshipsMap -> Maybe Text noRelBetweenHint parent child schema allRels = ("Perhaps you meant '" <>) <$> - if isJust (findMatch parent) + if isJust findParent then (<> "' instead of '" <> child <> "'.") <$> suggestChild else (<> "' instead of '" <> parent <> "'.") <$> suggestParent where - findMatch val = HM.lookup (QualifiedIdentifier schema val, schema) allRels + findParent = HM.lookup (QualifiedIdentifier schema parent, schema) allRels fuzzySetOfParents = Fuzzy.fromList [qiName (fst p) | p <- HM.keys allRels, snd p == schema] - fuzzySetOfChildren = Fuzzy.fromList [qiName (relForeignTable c) | c <- fromMaybe [] (findMatch parent)] + fuzzySetOfChildren = Fuzzy.fromList [qiName (relForeignTable c) | c <- fromMaybe [] findParent] suggestParent = Fuzzy.getOne fuzzySetOfParents parent - -- Do not suggest if the child is found in the relations (weight = 1.0) + -- Do not give suggestion if the child is found in the relations (weight = 1.0) suggestChild = headMay [snd k | k <- Fuzzy.get fuzzySetOfChildren child, fst k < 1.0] --- TODO: Maybe more complex suggestions are needed? E.g. both parent and child not found ---noRelBetweenHint parent child schema allRels = --- ("Perhaps you meant to select a relationship between '" <>) --- (<> ("instead of '" <> parent <> "' and '" <> child <> "'")) <$> --- case findMatch parent of --- Just rels -> ((parent <> "' and '") <>) <$> suggestChild rels --- _ -> findMatch --- where --- findMatch val = HM.lookup (QualifiedIdentifier schema val, schema) allRels --- fuzzySetOfParents = Fuzzy.fromList [qiName (fst p) | p <- rels, snd p == schema] --- fuzzySetOfChildren rels = Fuzzy.fromList [qiName (relForeignTable c) | c <- fromMaybe [] (findMatch parent)] --- suggestParent = Fuzzy.getOne fuzzySetOfParents parent --- suggestChild rels = Fuzzy.getOne (fuzzySetOfChildren rels) child -- | -- If no function is found with the given name, it does a fuzzy search to all the functions From 51774f5b84f1b52df7e8de71a14c09b5f109f9d8 Mon Sep 17 00:00:00 2001 From: Laurence Isla Date: Mon, 12 Dec 2022 19:32:10 -0500 Subject: [PATCH 3/8] Add spectests --- src/PostgREST/ApiRequest/Types.hs | 3 ++- test/spec/Feature/Query/EmbedDisambiguationSpec.hs | 12 ++++++------ test/spec/Feature/Query/QuerySpec.hs | 12 ++++++------ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/PostgREST/ApiRequest/Types.hs b/src/PostgREST/ApiRequest/Types.hs index 053f621890..3d0ec48961 100644 --- a/src/PostgREST/ApiRequest/Types.hs +++ b/src/PostgREST/ApiRequest/Types.hs @@ -35,7 +35,8 @@ import PostgREST.MediaType (MediaType (..)) import PostgREST.SchemaCache.Identifiers (FieldName, QualifiedIdentifier) import PostgREST.SchemaCache.Proc (ProcDescription (..)) -import PostgREST.SchemaCache.Relationship (Relationship, RelationshipsMap) +import PostgREST.SchemaCache.Relationship (Relationship, + RelationshipsMap) import Protolude diff --git a/test/spec/Feature/Query/EmbedDisambiguationSpec.hs b/test/spec/Feature/Query/EmbedDisambiguationSpec.hs index ffacc04e81..d99903d1ce 100644 --- a/test/spec/Feature/Query/EmbedDisambiguationSpec.hs +++ b/test/spec/Feature/Query/EmbedDisambiguationSpec.hs @@ -217,10 +217,10 @@ spec = it "fails if the fk is not known" $ get "/message?select=id,sender:person!space(name)&id=lt.4" `shouldRespondWith` [json|{ - "hint":"Verify that 'message' and 'person' exist in the schema 'test' and that there is a foreign key relationship between them. If a new relationship was created, try reloading the schema cache.", + "hint":null, "message":"Could not find a relationship between 'message' and 'person' in the schema cache", "code": "PGRST200", - "details": null}|] + "details":"Searched for a foreign key relationship between 'message' and 'person' using the hint 'space' in the schema 'test', but no matches were found."}|] { matchStatus = 400 , matchHeaders = [matchContentTypeJson] } @@ -507,10 +507,10 @@ spec = it "doesn't work if the junction is only internal" $ get "/end_1?select=end_2(*)" `shouldRespondWith` [json|{ - "hint":"Verify that 'end_1' and 'end_2' exist in the schema 'test' and that there is a foreign key relationship between them. If a new relationship was created, try reloading the schema cache.", + "hint": null, "message":"Could not find a relationship between 'end_1' and 'end_2' in the schema cache", "code":"PGRST200", - "details": null}|] + "details": "Searched for a foreign key relationship between 'end_1' and 'end_2' in the schema 'test', but no matches were found."}|] { matchStatus = 400 , matchHeaders = [matchContentTypeJson] } it "shouldn't try to embed if the private junction has an exposed homonym" $ @@ -518,10 +518,10 @@ spec = -- Ref: https://github.com/PostgREST/postgrest/issues/1587#issuecomment-734995669 get "/schauspieler?select=filme(*)" `shouldRespondWith` [json|{ - "hint":"Verify that 'schauspieler' and 'filme' exist in the schema 'test' and that there is a foreign key relationship between them. If a new relationship was created, try reloading the schema cache.", + "hint":null, "message":"Could not find a relationship between 'schauspieler' and 'filme' in the schema cache", "code":"PGRST200", - "details": null}|] + "details":"Searched for a foreign key relationship between 'schauspieler' and 'filme' in the schema 'test', but no matches were found."}|] { matchStatus = 400 , matchHeaders = [matchContentTypeJson] } diff --git a/test/spec/Feature/Query/QuerySpec.hs b/test/spec/Feature/Query/QuerySpec.hs index 8e2340f70f..7b4997aa4c 100644 --- a/test/spec/Feature/Query/QuerySpec.hs +++ b/test/spec/Feature/Query/QuerySpec.hs @@ -601,8 +601,8 @@ spec actualPgVersion = do it "cannot request a partitioned table as parent from a partition" $ get "/car_model_sales_202101?select=id,name,car_models(id,name)&order=id.asc" `shouldRespondWith` [json| - {"hint":"Verify that 'car_model_sales_202101' and 'car_models' exist in the schema 'test' and that there is a foreign key relationship between them. If a new relationship was created, try reloading the schema cache.", - "details":null, + {"hint":"Perhaps you meant 'car_model_sales' instead of 'car_model_sales_202101'.", + "details":"Searched for a foreign key relationship between 'car_model_sales_202101' and 'car_models' in the schema 'test', but no matches were found.", "code":"PGRST200", "message":"Could not find a relationship between 'car_model_sales_202101' and 'car_models' in the schema cache"} |] { matchStatus = 400 @@ -612,8 +612,8 @@ spec actualPgVersion = do it "cannot request a partition as parent from a partitioned table" $ get "/car_model_sales?id=in.(1,3,4)&select=id,name,car_models_default(id,name)&order=id.asc" `shouldRespondWith` [json| - {"hint":"Verify that 'car_model_sales' and 'car_models_default' exist in the schema 'test' and that there is a foreign key relationship between them. If a new relationship was created, try reloading the schema cache.", - "details":null, + {"hint":"Perhaps you meant 'car_models' instead of 'car_models_default'.", + "details":"Searched for a foreign key relationship between 'car_model_sales' and 'car_models_default' in the schema 'test', but no matches were found.", "code":"PGRST200", "message":"Could not find a relationship between 'car_model_sales' and 'car_models_default' in the schema cache"} |] { matchStatus = 400 @@ -623,8 +623,8 @@ spec actualPgVersion = do it "cannot request partitioned tables as children from a partition" $ get "/car_models_default?select=id,name,car_model_sales(id,name)&order=id.asc" `shouldRespondWith` [json| - {"hint":"Verify that 'car_models_default' and 'car_model_sales' exist in the schema 'test' and that there is a foreign key relationship between them. If a new relationship was created, try reloading the schema cache.", - "details":null, + {"hint":"Perhaps you meant 'car_model_sales' instead of 'car_models_default'.", + "details":"Searched for a foreign key relationship between 'car_models_default' and 'car_model_sales' in the schema 'test', but no matches were found.", "code":"PGRST200", "message":"Could not find a relationship between 'car_models_default' and 'car_model_sales' in the schema cache"} |] { matchStatus = 400 From cce368eae1892b2e240251a6714f3987c88a2efe Mon Sep 17 00:00:00 2001 From: Laurence Isla Date: Tue, 13 Dec 2022 20:34:55 -0500 Subject: [PATCH 4/8] Add changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b08bab2795..30bcf4c315 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - #2565, Fix bad M2M embedding on RPC - @steve-chavez - + - #2569, Replace misleading error message by parent and child name suggestions when no relationship is found - @laurenceisla ## [10.1.1] - 2022-11-08 ### Fixed From e15459eccb7e0842d9230712de966ea4d61d270d Mon Sep 17 00:00:00 2001 From: Laurence Isla Date: Tue, 13 Dec 2022 20:35:56 -0500 Subject: [PATCH 5/8] Add changelog for #2575 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30bcf4c315..7a3df77828 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - #2565, Fix bad M2M embedding on RPC - @steve-chavez + - #2575, Replace misleading error message by function and parameter name suggestions when no function is found - @laurenceisla - #2569, Replace misleading error message by parent and child name suggestions when no relationship is found - @laurenceisla ## [10.1.1] - 2022-11-08 From f6dbada0f43a963d698d675d4c51368a02f5f73b Mon Sep 17 00:00:00 2001 From: Laurence Isla Date: Tue, 13 Dec 2022 20:41:42 -0500 Subject: [PATCH 6/8] Use Schema instead of Text --- src/PostgREST/Error.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/PostgREST/Error.hs b/src/PostgREST/Error.hs index e5abbc311d..585e2c3399 100644 --- a/src/PostgREST/Error.hs +++ b/src/PostgREST/Error.hs @@ -37,7 +37,8 @@ import PostgREST.ApiRequest.Types (ApiRequestError (..), import PostgREST.MediaType (MediaType (..)) import qualified PostgREST.MediaType as MediaType -import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..)) +import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..), + Schema) import PostgREST.SchemaCache.Proc (ProcDescription (..), ProcParam (..)) import PostgREST.SchemaCache.Relationship (Cardinality (..), @@ -248,7 +249,7 @@ instance JSON.ToJSON ApiRequestError where -- >>> noRelBetweenHint "films" "noclosealternative" "noclosealternative" rels -- Nothing -- -noRelBetweenHint :: Text -> Text -> Text -> RelationshipsMap -> Maybe Text +noRelBetweenHint :: Text -> Text -> Schema -> RelationshipsMap -> Maybe Text noRelBetweenHint parent child schema allRels = ("Perhaps you meant '" <>) <$> if isJust findParent then (<> "' instead of '" <> child <> "'.") <$> suggestChild From f69f31404fd01460375d75f62270679eaa65a707 Mon Sep 17 00:00:00 2001 From: Laurence Isla Date: Wed, 14 Dec 2022 14:24:59 -0500 Subject: [PATCH 7/8] Clarify comment on function --- src/PostgREST/Error.hs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/PostgREST/Error.hs b/src/PostgREST/Error.hs index 585e2c3399..e6352b8ca9 100644 --- a/src/PostgREST/Error.hs +++ b/src/PostgREST/Error.hs @@ -218,10 +218,11 @@ instance JSON.ToJSON ApiRequestError where "hint" .= ("Try renaming the parameters or the function itself in the database so function overloading can be resolved" :: Text)] -- | --- If no relationship is found between a parent and a child, then it looks for the parent first. --- If the parent is not found then it does a fuzzy search to all the parents in the schema cache and --- gives the best match as suggestion. Otherwise, it does a fuzzy search to all the corresponding children --- of that parent and gives the best match as suggestion. If both are found, then no suggestion is given. +-- If no relationship is found then: +-- +-- Looks for parent suggestions if parent not found +-- Looks for child suggestions if parent is found but child is not +-- Gives no suggestions if both are found (it means that there is a problem with the embed hint) -- -- >>> :set -Wno-missing-fields -- >>> let qi t = QualifiedIdentifier "api" t From cf1fc3e85b08e083f10930fa76e2f81e929d3280 Mon Sep 17 00:00:00 2001 From: Steve Chavez Date: Thu, 15 Dec 2022 17:58:47 -0500 Subject: [PATCH 8/8] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a3df77828..8092f89ee4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,8 +23,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - #2565, Fix bad M2M embedding on RPC - @steve-chavez - - #2575, Replace misleading error message by function and parameter name suggestions when no function is found - @laurenceisla - - #2569, Replace misleading error message by parent and child name suggestions when no relationship is found - @laurenceisla + - #2575, Replace misleading error message when no function is found with a hint containing functions/parameters names suggestions - @laurenceisla + - #2569, Replace misleading error message when no relationship is found with a hint containing parent/child names suggestions - @laurenceisla ## [10.1.1] - 2022-11-08 ### Fixed