Merge pull request #386 from ruslantalpa/master

bugfix + Disambiguate range selection when plurality=singular
This commit is contained in:
Joe Nelson
2015-11-27 00:49:59 -08:00
4 changed files with 18 additions and 12 deletions
+5
View File
@@ -3,6 +3,11 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
## Unreleased
### Fixed
- Filter columns on embedded parent items - @ruslantalpa
## [0.3.0.0] - 2015-11-24 ## [0.3.0.0] - 2015-11-24
### Fixed ### Fixed
+2 -1
View File
@@ -20,6 +20,7 @@ import PostgREST.RangeQuery (NonnegRange, rangeRequested)
import PostgREST.Types (QualifiedIdentifier (..), import PostgREST.Types (QualifiedIdentifier (..),
Schema, Payload(..), Schema, Payload(..),
UniformObjects(..)) UniformObjects(..))
import Data.Ranged.Ranges (singletonRange)
type RequestBody = BL.ByteString type RequestBody = BL.ByteString
@@ -114,7 +115,7 @@ userApiRequest schema req reqBody =
ApiRequest { ApiRequest {
iAction = action iAction = action
, iRange = if singular then Nothing else rangeRequested hdrs , iRange = if singular then Just (singletonRange 0) else rangeRequested hdrs
, iTarget = target , iTarget = target
, iAccepts = pickContentType $ lookupHeader "accept" , iAccepts = pickContentType $ lookupHeader "accept"
, iPayload = relevantPayload , iPayload = relevantPayload
+7 -11
View File
@@ -34,7 +34,6 @@ import qualified Data.Aeson as JSON
import PostgREST.RangeQuery (NonnegRange, rangeLimit, rangeOffset) import PostgREST.RangeQuery (NonnegRange, rangeLimit, rangeOffset)
import Control.Error (note, fromMaybe, mapMaybe) import Control.Error (note, fromMaybe, mapMaybe)
import Data.Maybe (isNothing)
import Control.Monad (join) import Control.Monad (join)
import qualified Data.HashMap.Strict as HM import qualified Data.HashMap.Strict as HM
import Data.List (find) import Data.List (find)
@@ -55,8 +54,6 @@ import Data.Scientific ( FPFormat (..)
) )
import Prelude hiding (unwords) import Prelude hiding (unwords)
import Data.Ranged.Ranges (singletonRange)
type PStmt = H.Stmt P.Postgres type PStmt = H.Stmt P.Postgres
instance Monoid PStmt where instance Monoid PStmt where
mappend (B.Stmt query params prep) (B.Stmt query' params' prep') = mappend (B.Stmt query params prep) (B.Stmt query' params' prep') =
@@ -74,7 +71,7 @@ createReadStatement selectQuery range isSingle countTable asCsv =
if asCsv if asCsv
then asCsvF then asCsvF
else if isSingle then asJsonSingleF else asJsonF else if isSingle then asJsonSingleF else asJsonF
] selectStarF (if isNothing range && isSingle then Just $ singletonRange 0 else range) ] selectStarF range
) V.empty True ) V.empty True
createWriteStatement :: SqlQuery -> SqlQuery -> Bool -> Bool -> createWriteStatement :: SqlQuery -> SqlQuery -> Bool -> Bool ->
@@ -127,10 +124,9 @@ addJoinConditions schema (Node (query, (n, r)) forest) =
_ -> Left "unknown relation" _ -> Left "unknown relation"
where where
-- add parentTable and parentJoinConditions to the query -- add parentTable and parentJoinConditions to the query
updatedQuery = foldr (flip addCond) (query{from = parentTables ++ from query}) parentJoinConditions updatedQuery = foldr (flip addCond) query parentJoinConditions
where where
parentJoinConditions = map (getJoinConditions . snd) parents parentJoinConditions = map (getJoinConditions . snd) parents
parentTables = map fst parents
parents = mapMaybe (getParents . rootLabel) forest parents = mapMaybe (getParents . rootLabel) forest
getParents (_, (tbl, Just rel@(Relation{relType=Parent}))) = Just (tbl, rel) getParents (_, (tbl, Just rel@(Relation{relType=Parent}))) = Just (tbl, rel)
getParents _ = Nothing getParents _ = Nothing
@@ -198,14 +194,14 @@ requestToQuery schema (DbRead (Node (Select colSelects tbls conditions ord, (mai
qi = QualifiedIdentifier (tblSchema mainTbl) mainTbl qi = QualifiedIdentifier (tblSchema mainTbl) mainTbl
toQi t = QualifiedIdentifier (tblSchema t) t toQi t = QualifiedIdentifier (tblSchema t) t
query = unwords [ query = unwords [
("WITH " <> intercalate ", " withs) `emptyOnNull` withs, ("WITH " <> intercalate ", " (map fst withs)) `emptyOnNull` withs,
"SELECT ", intercalate ", " (map (pgFmtSelectItem qi) colSelects ++ selects), "SELECT ", intercalate ", " (map (pgFmtSelectItem qi) colSelects ++ selects),
"FROM ", intercalate ", " (map (fromQi . toQi) tbls), "FROM ", intercalate ", " (map (fromQi . toQi) tbls ++ map snd withs),
("WHERE " <> intercalate " AND " ( map (pgFmtCondition qi ) conditions )) `emptyOnNull` conditions, ("WHERE " <> intercalate " AND " ( map (pgFmtCondition qi ) conditions )) `emptyOnNull` conditions,
orderF (fromMaybe [] ord) orderF (fromMaybe [] ord)
] ]
(withs, selects) = foldr getQueryParts ([],[]) forest (withs, selects) = foldr getQueryParts ([],[]) forest
getQueryParts :: Tree ReadNode -> ([SqlFragment], [SqlFragment]) -> ([SqlFragment], [SqlFragment]) getQueryParts :: Tree ReadNode -> ([(SqlFragment, Text)], [SqlFragment]) -> ([(SqlFragment,Text)], [SqlFragment])
getQueryParts (Node n@(_, (table, Just (Relation {relType=Child}))) forst) (w,s) = (w,sel:s) getQueryParts (Node n@(_, (table, Just (Relation {relType=Child}))) forst) (w,s) = (w,sel:s)
where where
sel = "(" sel = "("
@@ -216,7 +212,7 @@ requestToQuery schema (DbRead (Node (Select colSelects tbls conditions ord, (mai
getQueryParts (Node n@(_, (table, Just (Relation {relType=Parent}))) forst) (w,s) = (wit:w,sel:s) getQueryParts (Node n@(_, (table, Just (Relation {relType=Parent}))) forst) (w,s) = (wit:w,sel:s)
where where
sel = "row_to_json(" <> table <> ".*) AS "<>table --TODO must be singular sel = "row_to_json(" <> table <> ".*) AS "<>table --TODO must be singular
wit = table <> " AS ( " <> subquery <> " )" wit = (table <> " AS ( " <> subquery <> " )", table)
where subquery = requestToQuery schema (DbRead (Node n forst)) where subquery = requestToQuery schema (DbRead (Node n forst))
getQueryParts (Node n@(_, (table, Just (Relation {relType=Many}))) forst) (w,s) = (w,sel:s) getQueryParts (Node n@(_, (table, Just (Relation {relType=Many}))) forst) (w,s) = (w,sel:s)
where where
@@ -331,7 +327,7 @@ getJoinConditions (Relation t cols ft fcs typ lt lc1 lc2) =
Parent -> zipWith (toFilter tN ftN) cols fcs Parent -> zipWith (toFilter tN ftN) cols fcs
Many -> zipWith (toFilter tN ltN) cols (fromMaybe [] lc1) ++ zipWith (toFilter ftN ltN) fcs (fromMaybe [] lc2) Many -> zipWith (toFilter tN ltN) cols (fromMaybe [] lc1) ++ zipWith (toFilter ftN ltN) fcs (fromMaybe [] lc2)
where where
s = tableSchema t s = if typ == Parent then "" else tableSchema t
tN = tableName t tN = tableName t
ftN = tableName ft ftN = tableName ft
ltN = fromMaybe "" (tableName <$> lt) ltN = fromMaybe "" (tableName <$> lt)
+4
View File
@@ -198,6 +198,10 @@ spec =
get "/projects?id=eq.1&select=id, name, clients{*}, tasks{id, name}" `shouldRespondWith` get "/projects?id=eq.1&select=id, name, clients{*}, tasks{id, name}" `shouldRespondWith`
"[{\"id\":1,\"name\":\"Windows 7\",\"clients\":{\"id\":1,\"name\":\"Microsoft\"},\"tasks\":[{\"id\":1,\"name\":\"Design w7\"},{\"id\":2,\"name\":\"Code w7\"}]}]" "[{\"id\":1,\"name\":\"Windows 7\",\"clients\":{\"id\":1,\"name\":\"Microsoft\"},\"tasks\":[{\"id\":1,\"name\":\"Design w7\"},{\"id\":2,\"name\":\"Code w7\"}]}]"
it "requesting parents and filtering parent columns" $
get "/projects?id=eq.1&select=id, name, clients{id}" `shouldRespondWith`
"[{\"id\":1,\"name\":\"Windows 7\",\"clients\":{\"id\":1}}]"
it "requesting children 2 levels" $ it "requesting children 2 levels" $
get "/clients?id=eq.1&select=id,projects{id,tasks{id}}" `shouldRespondWith` get "/clients?id=eq.1&select=id,projects{id,tasks{id}}" `shouldRespondWith`
"[{\"id\":1,\"projects\":[{\"id\":1,\"tasks\":[{\"id\":1},{\"id\":2}]},{\"id\":2,\"tasks\":[{\"id\":3},{\"id\":4}]}]}]" "[{\"id\":1,\"projects\":[{\"id\":1,\"tasks\":[{\"id\":1},{\"id\":2}]},{\"id\":2,\"tasks\":[{\"id\":3},{\"id\":4}]}]}]"