fix: empty spread embeddings return unexpected SQL error

Fixes the SQL error from postgres when an empty spread embeddings
like `...table()` is requested.
This commit is contained in:
Taimoor Zaeem
2025-07-13 14:16:27 -05:00
committed by Steve Chavez
parent d31c873cd5
commit d4caa0f5f5
3 changed files with 41 additions and 6 deletions
+1
View File
@@ -16,6 +16,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Fix OpenAPI broken docs link by @taimoorzaeem in #4080
- Fix OpenAPI specification incorrectly exposing GET methods for volatile functions by @joelonsql in #4174
- Fix empty spread embeddings return unexpected SQL error by @taimoorzaeem in #3887
### Changed
+6 -6
View File
@@ -69,21 +69,21 @@ readPlanToQuery node@(Node ReadPlan{select,from=mainQi,fromAlias,where_=logicFor
getJoinSelects :: ReadPlanTree -> [SQL.Snippet]
getJoinSelects (Node ReadPlan{relSelect} _) =
mapMaybe relSelectToSnippet relSelect
join $ map relSelectToSnippet relSelect
where
relSelectToSnippet :: RelSelectField -> Maybe SQL.Snippet
relSelectToSnippet :: RelSelectField -> [SQL.Snippet]
relSelectToSnippet fld =
let aggAlias = pgFmtIdent $ rsAggAlias fld
in
case fld of
JsonEmbed{rsEmptyEmbed = True} ->
Nothing
[]
JsonEmbed{rsSelName, rsEmbedMode = JsonObject} ->
Just $ "row_to_json(" <> aggAlias <> ".*)::jsonb AS " <> pgFmtIdent rsSelName
["row_to_json(" <> aggAlias <> ".*)::jsonb AS " <> pgFmtIdent rsSelName]
JsonEmbed{rsSelName, rsEmbedMode = JsonArray} ->
Just $ "COALESCE( " <> aggAlias <> "." <> aggAlias <> ", '[]') AS " <> pgFmtIdent rsSelName
["COALESCE( " <> aggAlias <> "." <> aggAlias <> ", '[]') AS " <> pgFmtIdent rsSelName]
Spread{rsSpreadSel, rsAggAlias} ->
Just $ intercalateSnippet ", " (pgFmtSpreadSelectItem rsAggAlias <$> rsSpreadSel)
pgFmtSpreadSelectItem rsAggAlias <$> rsSpreadSel
getJoins :: ReadPlanTree -> [SQL.Snippet]
getJoins (Node _ []) = []
@@ -600,3 +600,37 @@ spec =
{ matchStatus = 200
, matchHeaders = [matchContentTypeJson]
}
context "empty spreads embeds" $
it "should work return the same as empty embeddings" $ do
get "/actors?select=*,...films()"
`shouldRespondWith`
[json| [{"id":1,"name":"john"}, {"id":2,"name":"mary"}] |]
{ matchStatus = 200
, matchHeaders = [matchContentTypeJson]
}
get "/grandchild_entities?select=name,...child_entities(parent_name:name,...entities())"
`shouldRespondWith`
[json|
[{"name":"grandchild entity 1","parent_name":"child entity 1"},
{"name":"grandchild entity 2","parent_name":"child entity 1"},
{"name":"grandchild entity 3","parent_name":"child entity 2"},
{"name":"(grandchild,entity,4)","parent_name":"child entity 2"},
{"name":"(grandchild,entity,5)","parent_name":"child entity 2"}]
|]
{ matchStatus = 200
, matchHeaders = [matchContentTypeJson]
}
get "/factories?select=factory:name,...processes()"
`shouldRespondWith`
[json|
[{"factory":"Factory A"},
{"factory":"Factory B"},
{"factory":"Factory C"},
{"factory":"Factory D"}]
|]
{ matchStatus = 200
, matchHeaders = [matchContentTypeJson]
}