Compare commits

..
6 Commits
Author SHA1 Message Date
Joe Nelson 19b856db3b v0.3.0.1 2015-11-27 13:04:47 -08:00
Joe Nelson 4b911263e3 Merge pull request #386 from ruslantalpa/master
bugfix + Disambiguate range selection when plurality=singular
2015-11-27 00:49:59 -08:00
Ruslan Talpa c0fa5c3d4a changelog entry 2015-11-25 10:13:34 +02:00
Ruslan Talpa b3055888c5 Merge remote-tracking branch 'begriffs/master' 2015-11-25 10:10:11 +02:00
Ruslan Talpa 48ee77a64d bugfix: filter columns on embeded parent objects 2015-11-24 12:53:50 +02:00
Ruslan Talpa f678dff735 disambiguate range selection when plurality=singular 2015-11-24 09:39:44 +02:00
6 changed files with 21 additions and 14 deletions
+6
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/).
## [0.3.0.1] - 2015-11-27
### Fixed
- Filter columns on embedded parent items - @ruslantalpa
## [0.3.0.0] - 2015-11-24 ## [0.3.0.0] - 2015-11-24
### Fixed ### Fixed
@@ -25,6 +30,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Changed ### Changed
- Embed foreign keys with {} rather than () - @begriffs - Embed foreign keys with {} rather than () - @begriffs
- Remove version number from binary filename in release - @begriffs
## [0.2.12.1] - 2015-11-12 ## [0.2.12.1] - 2015-11-12
+1 -1
View File
@@ -10,7 +10,7 @@
}, },
"POSTGREST_VER": { "POSTGREST_VER": {
"description": "Version of PostgREST to deploy", "description": "Version of PostgREST to deploy",
"value": "0.3.0.0" "value": "0.3.0.1"
}, },
"DB_NAME": { "DB_NAME": {
"description": "Database name", "description": "Database name",
+1 -1
View File
@@ -2,7 +2,7 @@ name: postgrest
description: Reads the schema of a PostgreSQL database and creates RESTful routes description: Reads the schema of a PostgreSQL database and creates RESTful routes
for the tables and views, supporting all HTTP verbs that security for the tables and views, supporting all HTTP verbs that security
permits. permits.
version: 0.3.0.0 version: 0.3.0.1
synopsis: REST API for any Postgres database synopsis: REST API for any Postgres database
license: MIT license: MIT
license-file: LICENSE license-file: LICENSE
+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}]}]}]"