Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19b856db3b | ||
|
|
4b911263e3 | ||
|
|
c0fa5c3d4a | ||
|
|
b3055888c5 | ||
|
|
48ee77a64d | ||
|
|
f678dff735 |
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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}]}]}]"
|
||||||
|
|||||||
Reference in New Issue
Block a user