Merge remote-tracking branch 'begriffs/master'

This commit is contained in:
Ruslan Talpa
2015-09-07 09:28:31 +03:00
14 changed files with 232 additions and 189 deletions
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## Unreleased
### Added
- Filter columns, e.g. `?select=col1,col2` - @ruslantalpa
## [0.2.11.1] - 2015-09-01
### Fixed
- Accepts `*/*` in Accept header - @diogob
## [0.2.11.0] - 2015-08-28
### Added
- Negate any filter in a uniform way, e.g. `?col=not.eq=foo` - @diogob
+11 -1
View File
@@ -10,7 +10,7 @@
},
"POSTGREST_VER": {
"description": "Version of PostgREST to deploy",
"value": "0.2.11.0"
"value": "0.2.11.1"
},
"DB_NAME": {
"description": "Database name",
@@ -41,6 +41,16 @@
"description": "Maximum number of connections in database pool",
"required": false,
"value": "10"
},
"JWT_SECRET": {
"description": "Secret used to encrypt JSON Web Tokens",
"required": false,
"value": "secret"
},
"V1SCHEMA": {
"description": "DB schema selected whe no version (or version 1) requested",
"required": false,
"value": "1"
}
}
}
+1 -1
View File
@@ -2,7 +2,7 @@ name: postgrest
description: Reads the schema of a PostgreSQL database and creates RESTful routes
for the tables and views, supporting all HTTP verbs that security
permits.
version: 0.2.11.0
version: 0.2.11.1
synopsis: REST API for any Postgres database
license: MIT
license-file: LICENSE
+1 -1
View File
@@ -1,6 +1,6 @@
export POSTGREST_VER=`grep ^version /app/postgrest.cabal | sed -En 's/.*\s+([0-9\.]+)/\1/p'`
curl -L http://softlayer-ams.dl.sourceforge.net/project/s3tools/s3cmd/1.5.0-alpha1/s3cmd-1.5.0-alpha1.tar.gz | tar zx
curl -L http://sourceforge.net/projects/s3tools/files/s3cmd/1.5.0-alpha1/s3cmd-1.5.0-alpha1.tar.gz | tar zx
cp /app/dist/build/postgrest/postgrest postgrest-${POSTGREST_VER}
tar cJf postgrest-${POSTGREST_VER}.tar.xz postgrest-${POSTGREST_VER}
+12 -10
View File
@@ -119,8 +119,7 @@ app conf reqBody req =
encode . object $ [("message", String "Failed to parse user.")]
Just u -> do
setRole authenticator
login <- signInRole (cs $ userId u)
(cs $ userPass u)
login <- signInRole (cs $ userId u) (cs $ userPass u)
case login of
LoginSuccess role uid ->
return $ responseLBS status201 [ jsonH ] $
@@ -271,9 +270,9 @@ contentRangeH from to total =
("Content-Range",
if total == 0 || from > total
then "*/" <> cs (show total)
else cs (show from) <> "-"
<> cs (show to) <> "/"
<> cs (show total)
else cs (show from)
<> "-" <> cs (show to)
<> "/" <> cs (show total)
)
requestedSchema :: Text -> Maybe BS.ByteString -> Text
@@ -282,7 +281,8 @@ requestedSchema v1schema accept =
Just [[_, ver]] -> if ver == "1" then v1schema else cs ver
_ -> v1schema
where verRegex = "version[ ]*=[ ]*([0-9]+)" :: BS.ByteString
where
verRegex = "version[ ]*=[ ]*([0-9]+)" :: BS.ByteString
verStr = (=~ verRegex) <$> accept :: Maybe [[BS.ByteString]]
@@ -292,19 +292,21 @@ jsonMT = "application/json"
csvMT :: BS.ByteString
csvMT = "text/csv"
allMT :: BS.ByteString
allMT = "*/*"
jsonH :: Header
jsonH = (hContentType, jsonMT)
contentTypeForAccept :: Maybe BS.ByteString -> Maybe BS.ByteString
contentTypeForAccept accept
| isNothing accept || hasJson = Just jsonMT
| hasCsv = Just csvMT
| isNothing accept || has allMT || has jsonMT = Just jsonMT
| has csvMT = Just csvMT
| otherwise = Nothing
where
Just acceptH = accept
findInAccept = flip find $ parseHttpAccept acceptH
hasJson = isJust $ findInAccept $ BS.isPrefixOf jsonMT
hasCsv = isJust $ findInAccept $ BS.isPrefixOf csvMT
has = isJust . findInAccept . BS.isPrefixOf
bodyForAccept :: BS.ByteString -> QualifiedIdentifier -> StatementT
bodyForAccept contentType table
+4 -4
View File
@@ -56,10 +56,10 @@ setRole :: Text -> H.Tx P.Postgres s ()
setRole role = H.unitEx $ B.Stmt ("set local role " <> cs (pgFmtLit role)) V.empty True
setUserId :: Text -> H.Tx P.Postgres s ()
setUserId uid = if uid /= "" then
H.unitEx $ B.Stmt ("set local user_vars.user_id = " <> cs (pgFmtLit uid)) V.empty True
else
resetUserId
setUserId uid =
if uid /= ""
then H.unitEx $ B.Stmt ("set local user_vars.user_id = " <> cs (pgFmtLit uid)) V.empty True
else resetUserId
resetUserId :: H.Tx P.Postgres s ()
resetUserId = H.unitEx [H.stmt|reset user_vars.user_id|]
+6 -3
View File
@@ -65,11 +65,14 @@ main = do
poolSettings <- maybe (fail "Improper session settings") return $
H.poolSettings (fromIntegral $ configPool conf) 30
pool :: H.Pool P.Postgres
<- H.acquirePool pgSettings poolSettings
pool :: H.Pool P.Postgres <- H.acquirePool pgSettings poolSettings
resOrError <- H.session pool isServerVersionSupported
either (fail . show) (\supported -> unless supported $ fail "Cannot run in this PostgreSQL version, PostgREST needs at least 9.2.0") resOrError
either (fail . show)
(\supported ->
unless supported $
fail "Cannot run in this PostgreSQL version, PostgREST needs at least 9.2.0"
) resOrError
runSettings appSettings $ middle $ \req respond -> do
body <- strictRequestBody req
+13 -7
View File
@@ -105,7 +105,8 @@ asCsvWithCount :: QualifiedIdentifier -> StatementT
asCsvWithCount table = withCount . asCsv table
asCsv :: QualifiedIdentifier -> StatementT
asCsv table s = s { B.stmtTemplate =
asCsv table s = s {
B.stmtTemplate =
"(select string_agg(quote_ident(column_name::text), ',') from "
<> "(select column_name from information_schema.columns where quote_ident(table_schema) || '.' || table_name = '"
<> fromQi table <> "' order by ordinal_position) h) || '\r' || "
@@ -116,7 +117,8 @@ asJsonWithCount :: StatementT
asJsonWithCount = withCount . asJson
asJson :: StatementT
asJson s = s { B.stmtTemplate =
asJson s = s {
B.stmtTemplate =
"array_to_json(array_agg(row_to_json(t)))::character varying from ("
<> B.stmtTemplate s <> ") t" }
@@ -143,9 +145,13 @@ select table params =
selectTerm :: QualifiedIdentifier -> T.Text -> PStmt
selectTerm table col =
case T.splitOn "::" col of
[colName,castTo] -> B.Stmt ("CAST (" <> pgFmtJsonbPath table (cs colName) <> " AS " <> castToSafe <> " )" <> asT (jsonbPath colName)) empty True
[colName,castTo] ->
B.Stmt (
"CAST (" <> pgFmtJsonbPath table (cs colName) <> " AS "
<> castToSafe <> " )" <> asT (jsonbPath colName)
) empty True
where castToSafe = T.filter ( `elem` ['a'..'z'] ) castTo
_-> B.Stmt (pgFmtJsonbPath table (cs col) <> asT (jsonbPath col)) empty True
_ -> B.Stmt (pgFmtJsonbPath table (cs col) <> asT (jsonbPath col)) empty True
where
jsonbPath :: T.Text -> Maybe JsonbPath
jsonbPath c = parseJsonbPath $ cs c
@@ -216,9 +222,9 @@ wherePred table (col, predicate) =
opCode = hasNot (head rest) headPredicate
notOp = hasNot headPredicate ""
value = hasNot (T.intercalate "." $ tail rest) (T.intercalate "." rest)
whiteList val = fromMaybe (cs (pgFmtLit val) <> "::unknown ")
(L.find ((==) . T.toLower $ val)
["null","true","false"])
whiteList val = fromMaybe
(cs (pgFmtLit val) <> "::unknown ")
(L.find ((==) . T.toLower $ val) ["null","true","false"])
star c = if c == '*' then '%' else c
unknownLiteral = (<> "::unknown ") . pgFmtLit
+2 -1
View File
@@ -60,7 +60,8 @@ tables schema = do
and n.nspname = ?
and (
pg_has_role(c.relowner, 'USAGE'::text)
or has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER'::text) or has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES'::text)
or has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER'::text)
or has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES'::text)
)
order by relname
|] schema
+4 -4
View File
@@ -41,14 +41,14 @@ rangeRequested = (rangeParse =<<) . lookup hRange
rangeLimit :: NonnegRange -> Maybe Int
rangeLimit range =
case [rangeLower range, rangeUpper range]
of [BoundaryBelow from, BoundaryAbove to] -> Just (1 + to - from)
case [rangeLower range, rangeUpper range] of
[BoundaryBelow from, BoundaryAbove to] -> Just (1 + to - from)
_ -> Nothing
rangeOffset :: NonnegRange -> Int
rangeOffset range =
case rangeLower range
of BoundaryBelow from -> from
case rangeLower range of
BoundaryBelow from -> from
_ -> error "range without lower bound" -- should never happen
rangeGeq :: Int -> NonnegRange
+6
View File
@@ -261,6 +261,12 @@ spec = afterAll_ resetDb $ around withApp $ do
liftIO $ simpleHeaders g
`shouldSatisfy` matchHeader "Content-Range" "0-9/10"
it "can set a column to NULL" $ do
_ <- post "/no_pk" [json| { a: "keepme", b: "nullme" } |]
_ <- request methodPatch "/no_pk?b=eq.nullme" [] [json| { b: null } |]
get "/no_pk?a=eq.keepme" `shouldRespondWith`
[json| [{ a: "keepme", b: null }] |]
it "can update based on a computed column" $
request methodPatch
"/items?always_true=eq.false"
+5
View File
@@ -234,6 +234,11 @@ spec =
(acceptHdrs "text/unknowntype") ""
`shouldRespondWith` 415
it "should respond correctly to */* in accept header" $
request methodGet "/simple_pk"
(acceptHdrs "*/*") ""
`shouldRespondWith` 200
it "should respond correctly to multiple types in accept header" $
request methodGet "/simple_pk"
(acceptHdrs "text/unknowntype, text/csv") ""