Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
713b214c9a | ||
|
|
681388631b | ||
|
|
ae9e27a0c7 | ||
|
|
e83144ce7f | ||
|
|
1c54c7130a | ||
|
|
1a8d5fed8a | ||
|
|
57ebf43e85 | ||
|
|
b87734343e | ||
|
|
c80c9ef726 | ||
|
|
d5758523f3 | ||
|
|
ee40e7e0d7 | ||
|
|
53b606e1c1 |
@@ -0,0 +1,3 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
patreon: postgrest
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
|
<!--
|
||||||
|
Before reporting a bug:
|
||||||
|
If your database schema has changed while the PostgREST server is running, send the server a SIGUSR1 signal or restart it(http://postgrest.org/en/v5.2/admin.html#schema-reloading) to ensure the schema cache is not stale. This sometimes fixes apparent bugs.
|
||||||
|
-->
|
||||||
### Environment
|
### Environment
|
||||||
|
|
||||||
* PostgreSQL version: (if using docker, specify the image)
|
* PostgreSQL version: (if using docker, specify the image)
|
||||||
|
|||||||
+3
-1
@@ -29,16 +29,18 @@ PostgREST ongoing development is only possible thanks to our Sponsors and Backer
|
|||||||
## Lead Backers
|
## Lead Backers
|
||||||
|
|
||||||
- [Daniel Babiak](https://github.com/d-babiak)
|
- [Daniel Babiak](https://github.com/d-babiak)
|
||||||
- [Michel Pelletier](https://github.com/michelp/)
|
|
||||||
- Evans Fernandes
|
- Evans Fernandes
|
||||||
|
|
||||||
## Backers
|
## Backers
|
||||||
|
|
||||||
- Tsingson Qin
|
- Tsingson Qin
|
||||||
|
- Michel Pelletier
|
||||||
- Jay Hannah
|
- Jay Hannah
|
||||||
- Robert Stolarz
|
- Robert Stolarz
|
||||||
- Kofi Gumbs
|
- Kofi Gumbs
|
||||||
- Nicholas DiBiase
|
- Nicholas DiBiase
|
||||||
|
- Christopher Reid
|
||||||
|
- Nathan Bouscal
|
||||||
|
|
||||||
## Former Backers
|
## Former Backers
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,18 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
## [6.0.2] - 2019-08-22
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #1369, Change `raw-media-types` to accept a string of comma separated MIME types - @Dansvidania
|
||||||
|
- #1368, Fix long column descriptions being truncated at 63 characters in PostgreSQL 12 - @amedeedaboville
|
||||||
|
- #1348, Go back to converting plus "+" to space " " in querystrings by default - @steve-chavez
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- #1348, Deprecate `.` symbol for disambiguating resource embedding(added in #918). The url-safe '!' should be used instead. We refrained from using `+` as part of our syntax because it conflicts with some http clients and proxies.
|
||||||
|
|
||||||
## [6.0.1] - 2019-07-30
|
## [6.0.1] - 2019-07-30
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -50,13 +50,15 @@ Big thanks to our sponsors! You can join them by supporting PostgREST on [Patreo
|
|||||||
```bash
|
```bash
|
||||||
postgrest --help
|
postgrest --help
|
||||||
```
|
```
|
||||||
|
## [Documentation](http://postgrest.org)
|
||||||
|
|
||||||
|
Latest documentation is at [postgrest.org](http://postgrest.org). You can contribute to the docs in [PostgREST/postgrest-docs](https://github.com/PostgREST/postgrest-docs).
|
||||||
|
|
||||||
## Performance
|
## Performance
|
||||||
|
|
||||||
TLDR; subsecond response times for up to 2000 requests/sec on Heroku
|
TLDR; subsecond response times for up to 2000 requests/sec on Heroku
|
||||||
free tier. If you're used to servers written in interpreted languages
|
free tier. If you're used to servers written in interpreted languages,
|
||||||
(or named after precious gems), prepare to be pleasantly surprised by
|
prepare to be pleasantly surprised by PostgREST performance.
|
||||||
PostgREST performance.
|
|
||||||
|
|
||||||
Three factors contribute to the speed. First the server is written
|
Three factors contribute to the speed. First the server is written
|
||||||
in [Haskell](https://www.haskell.org/) using the
|
in [Haskell](https://www.haskell.org/) using the
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"POSTGREST_VER": {
|
"POSTGREST_VER": {
|
||||||
"description": "Version of PostgREST to deploy",
|
"description": "Version of PostgREST to deploy",
|
||||||
"value": "6.0.1"
|
"value": "6.0.2"
|
||||||
},
|
},
|
||||||
"DB_URI": {
|
"DB_URI": {
|
||||||
"description": "Database connection string, e.g. postgres://user:pass@xxxxxxx.rds.amazonaws.com/mydb",
|
"description": "Database connection string, e.g. postgres://user:pass@xxxxxxx.rds.amazonaws.com/mydb",
|
||||||
|
|||||||
@@ -16,5 +16,4 @@ role-claim-key = "$(PGRST_ROLE_CLAIM_KEY)"
|
|||||||
max-rows = "$(PGRST_MAX_ROWS)"
|
max-rows = "$(PGRST_MAX_ROWS)"
|
||||||
pre-request = "$(PGRST_PRE_REQUEST)"
|
pre-request = "$(PGRST_PRE_REQUEST)"
|
||||||
root-spec = "$(PGRST_ROOT_SPEC)"
|
root-spec = "$(PGRST_ROOT_SPEC)"
|
||||||
|
|
||||||
raw-media-types = "$(PGRST_RAW_MEDIA_TYPES)"
|
raw-media-types = "$(PGRST_RAW_MEDIA_TYPES)"
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
name: postgrest
|
name: postgrest
|
||||||
version: 6.0.1
|
version: 6.0.2
|
||||||
synopsis: REST API for any Postgres database
|
synopsis: REST API for any Postgres database
|
||||||
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
|
||||||
|
|||||||
@@ -138,14 +138,14 @@ userApiRequest schema rootSpec req reqBody
|
|||||||
, iCanonicalQS = toS $ urlEncodeVars
|
, iCanonicalQS = toS $ urlEncodeVars
|
||||||
. L.sortOn fst
|
. L.sortOn fst
|
||||||
. map (join (***) toS . second (fromMaybe BS.empty))
|
. map (join (***) toS . second (fromMaybe BS.empty))
|
||||||
$ queryStringWPlus
|
$ qString
|
||||||
, iJWT = tokenStr
|
, iJWT = tokenStr
|
||||||
, iHeaders = [ (toS $ CI.foldedCase k, toS v) | (k,v) <- hdrs, k /= hAuthorization, k /= hCookie]
|
, iHeaders = [ (toS $ CI.foldedCase k, toS v) | (k,v) <- hdrs, k /= hAuthorization, k /= hCookie]
|
||||||
, iCookies = maybe [] parseCookiesText $ lookupHeader "Cookie"
|
, iCookies = maybe [] parseCookiesText $ lookupHeader "Cookie"
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
-- queryString with '+' not converted to ' '
|
-- queryString with '+' converted to ' '(space)
|
||||||
queryStringWPlus = parseQueryReplacePlus False $ rawQueryString req
|
qString = parseQueryReplacePlus True $ rawQueryString req
|
||||||
-- rpcQParams = Rpc query params e.g. /rpc/name?param1=val1, similar to filter but with no operator(eq, lt..)
|
-- rpcQParams = Rpc query params e.g. /rpc/name?param1=val1, similar to filter but with no operator(eq, lt..)
|
||||||
(filters, rpcQParams) =
|
(filters, rpcQParams) =
|
||||||
case action of
|
case action of
|
||||||
@@ -215,7 +215,7 @@ userApiRequest schema rootSpec req reqBody
|
|||||||
path = pathInfo req
|
path = pathInfo req
|
||||||
method = requestMethod req
|
method = requestMethod req
|
||||||
hdrs = requestHeaders req
|
hdrs = requestHeaders req
|
||||||
qParams = [(toS k, v)|(k,v) <- queryStringWPlus]
|
qParams = [(toS k, v)|(k,v) <- qString]
|
||||||
lookupHeader = flip lookup hdrs
|
lookupHeader = flip lookup hdrs
|
||||||
hasPrefer :: Text -> Bool
|
hasPrefer :: Text -> Bool
|
||||||
hasPrefer val = any (\(h,v) -> h == "Prefer" && val `elem` split v) hdrs
|
hasPrefer val = any (\(h,v) -> h == "Prefer" && val `elem` split v) hdrs
|
||||||
|
|||||||
+6
-12
@@ -167,9 +167,9 @@ readOptions = do
|
|||||||
<*> pure False
|
<*> pure False
|
||||||
<*> (fmap (fmap coerceText) <$> C.subassocs "app.settings" C.value)
|
<*> (fmap (fmap coerceText) <$> C.subassocs "app.settings" C.value)
|
||||||
<*> (maybe (Right [JSPKey "role"]) parseRoleClaimKey <$> optValue "role-claim-key")
|
<*> (maybe (Right [JSPKey "role"]) parseRoleClaimKey <$> optValue "role-claim-key")
|
||||||
<*> (maybe ["public"] splitExtraSearchPath <$> optValue "db-extra-search-path")
|
<*> (maybe ["public"] splitOnCommas <$> optValue "db-extra-search-path")
|
||||||
<*> ((\x y -> QualifiedIdentifier x <$> y) <$> dbSchema <*> optString "root-spec")
|
<*> ((\x y -> QualifiedIdentifier x <$> y) <$> dbSchema <*> optString "root-spec")
|
||||||
<*> (fmap encodeUtf8 <$> optionalListOfText "raw-media-types")
|
<*> (maybe [] (fmap encodeUtf8 . splitOnCommas) <$> optValue "raw-media-types")
|
||||||
|
|
||||||
parseJwtAudience :: C.Key -> C.Parser C.Config (Maybe StringOrURI)
|
parseJwtAudience :: C.Key -> C.Parser C.Config (Maybe StringOrURI)
|
||||||
parseJwtAudience k =
|
parseJwtAudience k =
|
||||||
@@ -180,12 +180,6 @@ readOptions = do
|
|||||||
(Just "") -> pure Nothing
|
(Just "") -> pure Nothing
|
||||||
aud' -> pure aud'
|
aud' -> pure aud'
|
||||||
|
|
||||||
optionalListOfText :: C.Key -> C.Parser C.Config [Text]
|
|
||||||
optionalListOfText k =
|
|
||||||
C.optional k (C.list C.string) >>= \case
|
|
||||||
Nothing -> pure []
|
|
||||||
Just types -> pure types
|
|
||||||
|
|
||||||
reqString :: C.Key -> C.Parser C.Config Text
|
reqString :: C.Key -> C.Parser C.Config Text
|
||||||
reqString k = C.required k C.string
|
reqString k = C.required k C.string
|
||||||
|
|
||||||
@@ -219,9 +213,9 @@ readOptions = do
|
|||||||
parseRoleClaimKey (C.String s) = pRoleClaimKey s
|
parseRoleClaimKey (C.String s) = pRoleClaimKey s
|
||||||
parseRoleClaimKey v = pRoleClaimKey $ show v
|
parseRoleClaimKey v = pRoleClaimKey $ show v
|
||||||
|
|
||||||
splitExtraSearchPath :: C.Value -> [Text]
|
splitOnCommas :: C.Value -> [Text]
|
||||||
splitExtraSearchPath (C.String s) = strip <$> splitOn "," s
|
splitOnCommas (C.String s) = strip <$> splitOn "," s
|
||||||
splitExtraSearchPath _ = []
|
splitOnCommas _ = []
|
||||||
|
|
||||||
opts = info (helper <*> pathParser) $
|
opts = info (helper <*> pathParser) $
|
||||||
fullDesc
|
fullDesc
|
||||||
@@ -283,7 +277,7 @@ readOptions = do
|
|||||||
|# root-spec = "stored_proc_name"
|
|# root-spec = "stored_proc_name"
|
||||||
|
|
|
|
||||||
|## content types to produce raw output
|
|## content types to produce raw output
|
||||||
|# raw-media-types=["image/png","image/jpg"]
|
|# raw-media-types="image/png, image/jpg"
|
||||||
|]
|
|]
|
||||||
|
|
||||||
pathParser :: Parser FilePath
|
pathParser :: Parser FilePath
|
||||||
|
|||||||
@@ -437,7 +437,7 @@ allColumns tabs =
|
|||||||
nc.nspname::information_schema.sql_identifier AS table_schema,
|
nc.nspname::information_schema.sql_identifier AS table_schema,
|
||||||
c.relname::information_schema.sql_identifier AS table_name,
|
c.relname::information_schema.sql_identifier AS table_name,
|
||||||
a.attname::information_schema.sql_identifier AS column_name,
|
a.attname::information_schema.sql_identifier AS column_name,
|
||||||
d.description::information_schema.sql_identifier AS description,
|
d.description AS description,
|
||||||
a.attnum::information_schema.cardinal_number AS ordinal_position,
|
a.attnum::information_schema.cardinal_number AS ordinal_position,
|
||||||
pg_get_expr(ad.adbin, ad.adrelid)::information_schema.character_data AS column_default,
|
pg_get_expr(ad.adbin, ad.adrelid)::information_schema.character_data AS column_default,
|
||||||
CASE
|
CASE
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ instance JSON.ToJSON SimpleError where
|
|||||||
toJSON GucHeadersError = JSON.object [
|
toJSON GucHeadersError = JSON.object [
|
||||||
"message" .= ("response.headers guc must be a JSON array composed of objects with a single key and a string value" :: Text)]
|
"message" .= ("response.headers guc must be a JSON array composed of objects with a single key and a string value" :: Text)]
|
||||||
toJSON (BinaryFieldError ct) = JSON.object [
|
toJSON (BinaryFieldError ct) = JSON.object [
|
||||||
"message" .= ((toS (toMime ct) <> " requested but a single column was not selected") :: Text)]
|
"message" .= ((toS (toMime ct) <> " requested but more than one column was selected") :: Text)]
|
||||||
toJSON ConnectionLostError = JSON.object [
|
toJSON ConnectionLostError = JSON.object [
|
||||||
"message" .= ("Database connection lost, retrying the connection." :: Text)]
|
"message" .= ("Database connection lost, retrying the connection." :: Text)]
|
||||||
|
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ makePathItem (t, cs, _) = ("/" ++ unpack tn, p $ tableInsertable t)
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
postOp = tOp
|
postOp = tOp
|
||||||
& parameters .~ map ref ["body." <> tn, "preferReturn"]
|
& parameters .~ map ref ["body." <> tn, "select", "preferReturn"]
|
||||||
& at 201 ?~ "Created"
|
& at 201 ?~ "Created"
|
||||||
patchOp = tOp
|
patchOp = tOp
|
||||||
& parameters .~ map ref (rs <> ["body." <> tn, "preferReturn"])
|
& parameters .~ map ref (rs <> ["body." <> tn, "preferReturn"])
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ pRelationSelect = lexeme $ try ( do
|
|||||||
alias <- optionMaybe ( try(pFieldName <* aliasSeparator) )
|
alias <- optionMaybe ( try(pFieldName <* aliasSeparator) )
|
||||||
fld <- pField
|
fld <- pField
|
||||||
relationDetail <- optionMaybe (
|
relationDetail <- optionMaybe (
|
||||||
try ( char '+' *> pFieldName ) <|>
|
try ( char '!' *> pFieldName ) <|>
|
||||||
try ( char '.' *> pFieldName ) -- TODO deprecated, remove in next major version
|
try ( char '.' *> pFieldName ) -- TODO deprecated, remove in next major version
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+11
-10
@@ -480,12 +480,12 @@ spec actualPgVersion = do
|
|||||||
|
|
||||||
describe "path fixed" $ do
|
describe "path fixed" $ do
|
||||||
it "works when requesting children 2 levels" $
|
it "works when requesting children 2 levels" $
|
||||||
get "/clients?id=eq.1&select=id,projects:projects%2Bclient_id(id,tasks(id))" `shouldRespondWith`
|
get "/clients?id=eq.1&select=id,projects:projects!client_id(id,tasks(id))" `shouldRespondWith`
|
||||||
[json|[{"id":1,"projects":[{"id":1,"tasks":[{"id":1},{"id":2}]},{"id":2,"tasks":[{"id":3},{"id":4}]}]}]|]
|
[json|[{"id":1,"projects":[{"id":1,"tasks":[{"id":1},{"id":2}]},{"id":2,"tasks":[{"id":3},{"id":4}]}]}]|]
|
||||||
{ matchHeaders = [matchContentTypeJson] }
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
it "works with parent relation" $
|
it "works with parent relation" $
|
||||||
get "/message?select=id,body,sender:person%2Bsender(name),recipient:person%2Brecipient(name)&id=lt.4" `shouldRespondWith`
|
get "/message?select=id,body,sender:person!sender(name),recipient:person!recipient(name)&id=lt.4" `shouldRespondWith`
|
||||||
[json|
|
[json|
|
||||||
[{"id":1,"body":"Hello Jane","sender":{"name":"John"},"recipient":{"name":"Jane"}},
|
[{"id":1,"body":"Hello Jane","sender":{"name":"John"},"recipient":{"name":"Jane"}},
|
||||||
{"id":2,"body":"Hi John","sender":{"name":"Jane"},"recipient":{"name":"John"}},
|
{"id":2,"body":"Hi John","sender":{"name":"Jane"},"recipient":{"name":"John"}},
|
||||||
@@ -499,7 +499,7 @@ spec actualPgVersion = do
|
|||||||
, matchHeaders = [matchContentTypeJson] }
|
, matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
it "works with a parent view relation" $
|
it "works with a parent view relation" $
|
||||||
get "/message?select=id,body,sender:person_detail%2Bsender(name,sent),recipient:person_detail%2Brecipient(name,received)&id=lt.4" `shouldRespondWith`
|
get "/message?select=id,body,sender:person_detail!sender(name,sent),recipient:person_detail!recipient(name,received)&id=lt.4" `shouldRespondWith`
|
||||||
[json|
|
[json|
|
||||||
[{"id":1,"body":"Hello Jane","sender":{"name":"John","sent":2},"recipient":{"name":"Jane","received":2}},
|
[{"id":1,"body":"Hello Jane","sender":{"name":"John","sent":2},"recipient":{"name":"Jane","received":2}},
|
||||||
{"id":2,"body":"Hi John","sender":{"name":"Jane","sent":1},"recipient":{"name":"John","received":1}},
|
{"id":2,"body":"Hi John","sender":{"name":"Jane","sent":1},"recipient":{"name":"John","received":1}},
|
||||||
@@ -507,10 +507,11 @@ spec actualPgVersion = do
|
|||||||
{ matchHeaders = [matchContentTypeJson] }
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
it "works with many<->many relation" $
|
it "works with many<->many relation" $
|
||||||
get "/tasks?select=id,users:users%2Busers_tasks(id)" `shouldRespondWith`
|
get "/tasks?select=id,users:users!users_tasks(id)" `shouldRespondWith`
|
||||||
[json|[{"id":1,"users":[{"id":1},{"id":3}]},{"id":2,"users":[{"id":1}]},{"id":3,"users":[{"id":1}]},{"id":4,"users":[{"id":1}]},{"id":5,"users":[{"id":2},{"id":3}]},{"id":6,"users":[{"id":2}]},{"id":7,"users":[{"id":2}]},{"id":8,"users":[]}]|]
|
[json|[{"id":1,"users":[{"id":1},{"id":3}]},{"id":2,"users":[{"id":1}]},{"id":3,"users":[{"id":1}]},{"id":4,"users":[{"id":1}]},{"id":5,"users":[{"id":2},{"id":3}]},{"id":6,"users":[{"id":2}]},{"id":7,"users":[{"id":2}]},{"id":8,"users":[]}]|]
|
||||||
{ matchHeaders = [matchContentTypeJson] }
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
|
-- TODO Remove in next major version(7.0)
|
||||||
describe "old dot '.' symbol, deprecated" $
|
describe "old dot '.' symbol, deprecated" $
|
||||||
it "still works" $ do
|
it "still works" $ do
|
||||||
get "/clients?id=eq.1&select=id,projects:projects.client_id(id,tasks(id))" `shouldRespondWith`
|
get "/clients?id=eq.1&select=id,projects:projects.client_id(id,tasks(id))" `shouldRespondWith`
|
||||||
@@ -588,7 +589,7 @@ spec actualPgVersion = do
|
|||||||
{ matchHeaders = [matchContentTypeJson] }
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
it "embeds childs recursively" $
|
it "embeds childs recursively" $
|
||||||
get "/family_tree?id=eq.1&select=id,name, childs:family_tree%2Bparent(id,name,childs:family_tree%2Bparent(id,name))" `shouldRespondWith`
|
get "/family_tree?id=eq.1&select=id,name, childs:family_tree!parent(id,name,childs:family_tree!parent(id,name))" `shouldRespondWith`
|
||||||
[json|[{
|
[json|[{
|
||||||
"id": "1", "name": "Parental Unit", "childs": [
|
"id": "1", "name": "Parental Unit", "childs": [
|
||||||
{ "id": "2", "name": "Kid One", "childs": [ { "id": "4", "name": "Grandkid One" } ] },
|
{ "id": "2", "name": "Kid One", "childs": [ { "id": "4", "name": "Grandkid One" } ] },
|
||||||
@@ -597,7 +598,7 @@ spec actualPgVersion = do
|
|||||||
}]|] { matchHeaders = [matchContentTypeJson] }
|
}]|] { matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
it "embeds parent and then embeds childs" $
|
it "embeds parent and then embeds childs" $
|
||||||
get "/family_tree?id=eq.2&select=id,name,parent(id,name,childs:family_tree%2Bparent(id,name))" `shouldRespondWith`
|
get "/family_tree?id=eq.2&select=id,name,parent(id,name,childs:family_tree!parent(id,name))" `shouldRespondWith`
|
||||||
[json|[{
|
[json|[{
|
||||||
"id": "2", "name": "Kid One", "parent": {
|
"id": "2", "name": "Kid One", "parent": {
|
||||||
"id": "1", "name": "Parental Unit", "childs": [ { "id": "2", "name": "Kid One" }, { "id": "3", "name": "Kid Two"} ]
|
"id": "1", "name": "Parental Unit", "childs": [ { "id": "2", "name": "Kid One" }, { "id": "3", "name": "Kid Two"} ]
|
||||||
@@ -620,7 +621,7 @@ spec actualPgVersion = do
|
|||||||
}]|] { matchHeaders = [matchContentTypeJson] }
|
}]|] { matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
it "embeds childs" $ do
|
it "embeds childs" $ do
|
||||||
get "/organizations?select=id,name,refereeds:organizations%2Breferee(id,name)&id=eq.1" `shouldRespondWith`
|
get "/organizations?select=id,name,refereeds:organizations!referee(id,name)&id=eq.1" `shouldRespondWith`
|
||||||
[json|[{
|
[json|[{
|
||||||
"id": 1, "name": "Referee Org",
|
"id": 1, "name": "Referee Org",
|
||||||
"refereeds": [
|
"refereeds": [
|
||||||
@@ -634,7 +635,7 @@ spec actualPgVersion = do
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}]|] { matchHeaders = [matchContentTypeJson] }
|
}]|] { matchHeaders = [matchContentTypeJson] }
|
||||||
get "/organizations?select=id,name,auditees:organizations%2Bauditor(id,name)&id=eq.2" `shouldRespondWith`
|
get "/organizations?select=id,name,auditees:organizations!auditor(id,name)&id=eq.2" `shouldRespondWith`
|
||||||
[json|[{
|
[json|[{
|
||||||
"id": 2, "name": "Auditor Org",
|
"id": 2, "name": "Auditor Org",
|
||||||
"auditees": [
|
"auditees": [
|
||||||
@@ -668,7 +669,7 @@ spec actualPgVersion = do
|
|||||||
"manager":{"name":"Referee Manager"}}}
|
"manager":{"name":"Referee Manager"}}}
|
||||||
}]|] { matchHeaders = [matchContentTypeJson] }
|
}]|] { matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
get "/organizations?select=name,manager(name),auditees:organizations%2Bauditor(name,manager(name),refereeds:organizations%2Breferee(name,manager(name)))&id=eq.2" `shouldRespondWith`
|
get "/organizations?select=name,manager(name),auditees:organizations!auditor(name,manager(name),refereeds:organizations!referee(name,manager(name)))&id=eq.2" `shouldRespondWith`
|
||||||
[json|[{
|
[json|[{
|
||||||
"name":"Auditor Org",
|
"name":"Auditor Org",
|
||||||
"manager":{"name":"Auditor Manager"},
|
"manager":{"name":"Auditor Manager"},
|
||||||
@@ -950,7 +951,7 @@ spec actualPgVersion = do
|
|||||||
it "fails if a single column is not selected" $ do
|
it "fails if a single column is not selected" $ do
|
||||||
request methodGet "/images?select=img,name&name=eq.A.png" (acceptHdrs "application/octet-stream") ""
|
request methodGet "/images?select=img,name&name=eq.A.png" (acceptHdrs "application/octet-stream") ""
|
||||||
`shouldRespondWith`
|
`shouldRespondWith`
|
||||||
[json| {"message":"application/octet-stream requested but a single column was not selected"} |]
|
[json| {"message":"application/octet-stream requested but more than one column was selected"} |]
|
||||||
{ matchStatus = 406
|
{ matchStatus = 406
|
||||||
, matchHeaders = [matchContentTypeJson]
|
, matchHeaders = [matchContentTypeJson]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -482,7 +482,7 @@ spec actualPgVersion =
|
|||||||
it "fails if a single column is not selected" $
|
it "fails if a single column is not selected" $
|
||||||
request methodPost "/rpc/ret_rows_with_base64_bin" (acceptHdrs "application/octet-stream") ""
|
request methodPost "/rpc/ret_rows_with_base64_bin" (acceptHdrs "application/octet-stream") ""
|
||||||
`shouldRespondWith`
|
`shouldRespondWith`
|
||||||
[json| {"message":"application/octet-stream requested but a single column was not selected"} |]
|
[json| {"message":"application/octet-stream requested but more than one column was selected"} |]
|
||||||
{ matchStatus = 406
|
{ matchStatus = 406
|
||||||
, matchHeaders = [matchContentTypeJson]
|
, matchHeaders = [matchContentTypeJson]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ spec = do
|
|||||||
childGetSummary = r ^? method "get" . key "summary"
|
childGetSummary = r ^? method "get" . key "summary"
|
||||||
childGetDescription = r ^? method "get" . key "description"
|
childGetDescription = r ^? method "get" . key "description"
|
||||||
getParameters = r ^? method "get" . key "parameters"
|
getParameters = r ^? method "get" . key "parameters"
|
||||||
|
postParameters = r ^? method "post" . key "parameters"
|
||||||
postResponse = r ^? method "post" . key "responses" . key "201" . key "description"
|
postResponse = r ^? method "post" . key "responses" . key "201" . key "description"
|
||||||
patchResponse = r ^? method "patch" . key "responses" . key "204" . key "description"
|
patchResponse = r ^? method "patch" . key "responses" . key "204" . key "description"
|
||||||
deleteResponse = r ^? method "delete" . key "responses" . key "204" . key "description"
|
deleteResponse = r ^? method "delete" . key "responses" . key "204" . key "description"
|
||||||
@@ -79,6 +80,15 @@ spec = do
|
|||||||
]
|
]
|
||||||
|]
|
|]
|
||||||
|
|
||||||
|
postParameters `shouldBe` Just
|
||||||
|
[aesonQQ|
|
||||||
|
[
|
||||||
|
{ "$ref": "#/parameters/body.child_entities" },
|
||||||
|
{ "$ref": "#/parameters/select" },
|
||||||
|
{ "$ref": "#/parameters/preferReturn" }
|
||||||
|
]
|
||||||
|
|]
|
||||||
|
|
||||||
postResponse `shouldBe` Just "Created"
|
postResponse `shouldBe` Just "Created"
|
||||||
|
|
||||||
patchResponse `shouldBe` Just "No Content"
|
patchResponse `shouldBe` Just "No Content"
|
||||||
@@ -125,7 +135,7 @@ spec = do
|
|||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"description": "child_entities name comment",
|
"description": "child_entities name comment. Can be longer than sixty-three characters long",
|
||||||
"format": "text",
|
"format": "text",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1226,7 +1226,7 @@ create table ranges (
|
|||||||
|
|
||||||
comment on table child_entities is 'child_entities comment';
|
comment on table child_entities is 'child_entities comment';
|
||||||
comment on column child_entities.id is 'child_entities id comment';
|
comment on column child_entities.id is 'child_entities id comment';
|
||||||
comment on column child_entities.name is 'child_entities name comment';
|
comment on column child_entities.name is 'child_entities name comment. Can be longer than sixty-three characters long';
|
||||||
|
|
||||||
comment on table grandchild_entities is
|
comment on table grandchild_entities is
|
||||||
$$grandchild_entities summary
|
$$grandchild_entities summary
|
||||||
|
|||||||
Reference in New Issue
Block a user