Merge remote-tracking branch 'begriffs/v3' into v3

This commit is contained in:
Ruslan Talpa
2015-10-16 11:34:10 +03:00
13 changed files with 202 additions and 208 deletions
+5
View File
@@ -9,6 +9,11 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Embed associations, e.g. `/film?select=*,director(*)` - @ruslantalpa - Embed associations, e.g. `/film?select=*,director(*)` - @ruslantalpa
- Filter columns, e.g. `?select=col1,col2` - @ruslantalpa - Filter columns, e.g. `?select=col1,col2` - @ruslantalpa
- Does not execute the count total if header "Prefer: count=none" - @diogob - Does not execute the count total if header "Prefer: count=none" - @diogob
- Postgres connection string argument - @calebmer
### Removed
- API versioning feature - @calebmer
- `--db-x` command line arguments - @calebmer
### Fixed ### Fixed
- Tolerate a missing role in user creation - @calebmer - Tolerate a missing role in user creation - @calebmer
+15 -12
View File
@@ -24,13 +24,16 @@ your own projects.
Download the binary ([latest release](https://github.com/begriffs/postgrest/releases/latest)) and invoke like so: Download the binary ([latest release](https://github.com/begriffs/postgrest/releases/latest)) and invoke like so:
```bash ```bash
postgrest --db-host localhost --db-port 5432 \ postgrest postgres://postgres:foobar@localhost:5432/my_db \
--db-name my_db --db-user postgres \ --port 3000 \
--db-pass foobar --db-pool 200 \ --schema public \
--anonymous postgres --port 3000 \ --anonymous postgres \
--v1schema public --pool 200
``` ```
For more information on valid connection strings see the
[Postgres docs](http://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNSTRING).
In production include the `--secure` option which redirects all In production include the `--secure` option which redirects all
requests to HTTPS. Note that PostgREST does not handle the SSL requests to HTTPS. Note that PostgREST does not handle the SSL
internally and must be put behind another server that does (such internally and must be put behind another server that does (such
@@ -100,13 +103,14 @@ guide](https://github.com/begriffs/postgrest/wiki/Security-and-Permissions).
### Versioning ### Versioning
A robust long-lived API needs the freedom to exist in multiple A robust long-lived API needs the freedom to exist in multiple
versions. PostgREST supports versioning through HTTP content versions. Therefore it is a best practice that you version the database
negotiation. Requests for a certain version translate into switching schema exposed to PostgREST (e.g. `public1` or `api2`). This way you
which database schema to search for tables. PostgreSQL schema search future proof your API by allowing it to be backwards compatible when
paths allow tables from earlier versions to be reused verbatim in you want to publish breaking API changes (e.g. a later version could
later versions. be `public2` or `api3`).
To learn more, see the [guide to versioning](https://github.com/begriffs/postgrest/wiki/API-Versioning). For routing to different versions of a PostgREST API use a request
proxy (such as [nginx](http://nginx.org)).
### Self-documention ### Self-documention
@@ -153,7 +157,6 @@ and the [guide to routing](https://github.com/begriffs/postgrest/wiki/Routing).
### Guides ### Guides
* [Routing](https://github.com/begriffs/postgrest/wiki/Routing) * [Routing](https://github.com/begriffs/postgrest/wiki/Routing)
* [Versioning](https://github.com/begriffs/postgrest/wiki/API-Versioning)
* [Performance](https://github.com/begriffs/postgrest/wiki/Performance-and-Scaling) * [Performance](https://github.com/begriffs/postgrest/wiki/Performance-and-Scaling)
* [Security](https://github.com/begriffs/postgrest/wiki/Security-and-Permissions) * [Security](https://github.com/begriffs/postgrest/wiki/Security-and-Permissions)
* [Tutorial](http://blog.jonharrington.org/postgrest-introduction/) (external) * [Tutorial](http://blog.jonharrington.org/postgrest-introduction/) (external)
+6 -6
View File
@@ -2,12 +2,12 @@
### BEGIN INIT INFO ### BEGIN INIT INFO
# Provides: postgrest # Provides: postgrest
# Required-Start: $local_fs $network postgresql # Required-Start: $local_fs $network postgresql
# Required-Stop: $local_fs $network # Required-Stop: $local_fs $network
# Default-Start: 2 3 4 5 # Default-Start: 2 3 4 5
# Default-Stop: 0 1 6 # Default-Stop: 0 1 6
# Description: PostgreSQL REST API daemon # Description: PostgreSQL REST API daemon
### END INIT INFO ### END INIT INFO
. /lib/lsb/init-functions . /lib/lsb/init-functions
if test -f /etc/default/postgrest; then if test -f /etc/default/postgrest; then
. /etc/default/postgrest . /etc/default/postgrest
@@ -32,8 +32,8 @@ fi
if [ -n "$POSTGREST_DBPOOL" ]; then if [ -n "$POSTGREST_DBPOOL" ]; then
POSTGREST_OPTS="$POSTGREST_OPTS --db-pool $POSTGREST_DBPOOL" POSTGREST_OPTS="$POSTGREST_OPTS --db-pool $POSTGREST_DBPOOL"
fi fi
POSTGREST_OPTS="$POSTGREST_OPTS --v1schema public" POSTGREST_OPTS="$POSTGREST_OPTS --schema public"
start() start()
{ {
log_daemon_msg "Starting PostgreSQL REST API daemon" "postgrest" || true log_daemon_msg "Starting PostgreSQL REST API daemon" "postgrest" || true
@@ -43,7 +43,7 @@ start()
log_end_msg 1 || true log_end_msg 1 || true
fi fi
} }
stop() stop()
{ {
log_daemon_msg "Stopping PostgreSQL REST API daemon" "postgrest" || true log_daemon_msg "Stopping PostgreSQL REST API daemon" "postgrest" || true
@@ -53,7 +53,7 @@ stop()
log_end_msg 1 || true log_end_msg 1 || true
fi fi
} }
status() status()
{ {
status_of_proc $POSTGREST postgrest && exit 0 || exit $? status_of_proc $POSTGREST postgrest && exit 0 || exit $?
+1
View File
@@ -37,6 +37,7 @@ executable postgrest
, case-insensitive , case-insensitive
, scientific, time , scientific, time
, aeson >= 0.8, network >= 2.6 , aeson >= 0.8, network >= 2.6
, aeson-pretty >= 0.7 && < 0.8
, bytestring, text, split, string-conversions , bytestring, text, split, string-conversions
, stringsearch , stringsearch
, containers, unordered-containers , containers, unordered-containers
+4 -18
View File
@@ -6,7 +6,6 @@ module PostgREST.App (
, isSqlError , isSqlError
, contentTypeForAccept , contentTypeForAccept
, jsonH , jsonH
, requestedSchema
, TableOptions(..) , TableOptions(..)
) where ) where
@@ -29,7 +28,6 @@ import Data.Ranged.Ranges (emptyRange)
import qualified Data.Set as S import qualified Data.Set as S
import Data.String.Conversions (cs) import Data.String.Conversions (cs)
import Data.Text (Text, replace, strip) import Data.Text (Text, replace, strip)
import Text.Regex.TDFA ((=~))
import Text.Parsec.Error import Text.Parsec.Error
@@ -59,8 +57,8 @@ import PostgREST.Types
import Prelude import Prelude
app :: DbStructure -> AppConfig -> BL.ByteString -> DbRole -> Request -> H.Tx P.Postgres s Response app :: DbStructure -> AppConfig -> DbRole -> BL.ByteString -> DbRole -> Request -> H.Tx P.Postgres s Response
app dbstructure conf reqBody dbrole req = app dbstructure conf authenticator reqBody dbrole req =
case (path, verb) of case (path, verb) of
([], _) -> do ([], _) -> do
@@ -216,7 +214,7 @@ app dbstructure conf reqBody dbrole req =
-- check that proc exists -- check that proc exists
-- check that arg names are all specified -- check that arg names are all specified
-- select * from "1".proc(a := "foo"::undefined) where whereT limit limitT -- select * from public.proc(a := "foo"::undefined) where whereT limit limitT
([table], "PUT") -> ([table], "PUT") ->
handleJsonObj reqBody $ \obj -> do handleJsonObj reqBody $ \obj -> do
@@ -296,8 +294,7 @@ app dbstructure conf reqBody dbrole req =
lookupHeader = flip lookup hdrs lookupHeader = flip lookup hdrs
hasPrefer val = any (\(h,v) -> h == "Prefer" && v == val) hdrs hasPrefer val = any (\(h,v) -> h == "Prefer" && v == val) hdrs
accept = lookupHeader hAccept accept = lookupHeader hAccept
schema = requestedSchema (cs $ configV1Schema conf) accept schema = cs $ configSchema conf
authenticator = cs $ configDbUser conf
jwtSecret = cs $ configJwtSecret conf jwtSecret = cs $ configJwtSecret conf
range = rangeRequested hdrs range = rangeRequested hdrs
allOrigins = ("Access-Control-Allow-Origin", "*") :: Header allOrigins = ("Access-Control-Allow-Origin", "*") :: Header
@@ -329,17 +326,6 @@ contentRangeH from to total =
totalNotZero = fromMaybe True ((/=) 0 <$> total) totalNotZero = fromMaybe True ((/=) 0 <$> total)
fromInRange = from <= to fromInRange = from <= to
requestedSchema :: Text -> Maybe BS.ByteString -> Text
requestedSchema v1schema accept =
case verStr of
Just [[_, ver]] -> if ver == "1" then v1schema else cs ver
_ -> v1schema
where
verRegex = "version[ ]*=[ ]*([0-9]+)" :: BS.ByteString
verStr = (=~ verRegex) <$> accept :: Maybe [[BS.ByteString]]
jsonMT :: BS.ByteString jsonMT :: BS.ByteString
jsonMT = "application/json" jsonMT = "application/json"
+10 -19
View File
@@ -34,34 +34,25 @@ import Prelude
-- | Data type to store all command line options -- | Data type to store all command line options
data AppConfig = AppConfig { data AppConfig = AppConfig {
configDbName :: String configDatabase :: String
, configDbPort :: Int
, configDbUser :: String
, configDbPass :: String
, configDbHost :: String
, configPort :: Int , configPort :: Int
, configAnonRole :: String , configAnonRole :: String
, configSchema :: String
, configSecure :: Bool , configSecure :: Bool
, configPool :: Int
, configV1Schema :: String
, configJwtSecret :: String , configJwtSecret :: String
, configPool :: Int
} }
argParser :: Parser AppConfig argParser :: Parser AppConfig
argParser = AppConfig argParser = AppConfig
<$> strOption (long "db-name" <> short 'd' <> metavar "NAME" <> help "name of database") <$> argument str (help "database connection string" <> metavar "STRING")
<*> option auto (long "db-port" <> short 'P' <> metavar "PORT" <> value 5432 <> help "postgres server port" <> showDefault)
<*> strOption (long "db-user" <> short 'U' <> metavar "ROLE" <> help "postgres authenticator role")
<*> strOption (long "db-pass" <> metavar "PASS" <> value "" <> help "password for authenticator role")
<*> strOption (long "db-host" <> metavar "HOST" <> value "localhost" <> help "postgres server hostname" <> showDefault)
<*> option auto (long "port" <> short 'p' <> metavar "PORT" <> value 3000 <> help "port number on which to run HTTP server" <> showDefault) <*> option auto (long "port" <> short 'p' <> help "port number on which to run HTTP server" <> metavar "PORT" <> value 3000 <> showDefault)
<*> strOption (long "anonymous" <> short 'a' <> metavar "ROLE" <> help "postgres role to use for non-authenticated requests") <*> strOption (long "anonymous" <> short 'a' <> help "postgres role to use for non-authenticated requests" <> metavar "ROLE")
<*> switch (long "secure" <> short 's' <> help "Redirect all requests to HTTPS") <*> strOption (long "schema" <> short 'S' <> help "schema to use for API routes" <> metavar "NAME" <> value "1" <> showDefault)
<*> option auto (long "db-pool" <> metavar "COUNT" <> value 10 <> help "Max connections in database pool" <> showDefault) <*> switch (long "secure" <> short 's' <> help "redirect all requests to HTTPS")
<*> strOption (long "v1schema" <> metavar "NAME" <> value "1" <> help "Schema to use for nonspecified version (or explicit v1)" <> showDefault) <*> strOption (long "jwt-secret" <> short 'j' <> help "secret used to encrypt and decrypt JWT tokens" <> metavar "SECRET" <> value "secret" <> showDefault)
<*> strOption (long "jwt-secret" <> metavar "SECRET" <> value "secret" <> help "Secret used to encrypt and decrypt JWT tokens)" <> showDefault) <*> option auto (long "pool" <> short 'o' <> help "max connections in database pool" <> metavar "COUNT" <> value 10 <> showDefault)
defaultCorsPolicy :: CorsResourcePolicy defaultCorsPolicy :: CorsResourcePolicy
defaultCorsPolicy = CorsResourcePolicy Nothing defaultCorsPolicy = CorsResourcePolicy Nothing
+28 -23
View File
@@ -1,39 +1,41 @@
module Main where module Main where
import PostgREST.App
import PostgREST.Config (AppConfig (..),
minimumPgVersion,
prettyVersion,
readOptions)
import PostgREST.Error (errResponse, PgError)
import PostgREST.Middleware
import PostgREST.PgStructure import PostgREST.PgStructure
import PostgREST.Types import PostgREST.Types
import Network.Wai
import PostgREST.App
import PostgREST.Error (errResponse)
import PostgREST.Middleware
import Control.Monad (unless) import Control.Monad (unless)
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import Data.Aeson.Encode.Pretty (encodePretty)
import Data.Functor.Identity import Data.Functor.Identity
import Data.Monoid ((<>)) import Data.Monoid ((<>))
import Data.String.Conversions (cs) import Data.String.Conversions (cs)
import Data.Text (Text) import Data.Text (Text)
import qualified Hasql as H import qualified Hasql as H
import qualified Hasql.Postgres as P import qualified Hasql.Postgres as P
import Network.Wai
import Network.Wai.Handler.Warp hiding (Connection) import Network.Wai.Handler.Warp hiding (Connection)
import Network.Wai.Middleware.RequestLogger (logStdout) import Network.Wai.Middleware.RequestLogger (logStdout)
import System.IO (BufferMode (..), import System.IO (BufferMode (..),
hSetBuffering, stderr, hSetBuffering, stderr,
stdin, stdout) stdin, stdout)
import PostgREST.Config (AppConfig (..),
prettyVersion,
readOptions,
minimumPgVersion)
isServerVersionSupported :: H.Session P.Postgres IO Bool isServerVersionSupported :: H.Session P.Postgres IO Bool
isServerVersionSupported = do isServerVersionSupported = do
Identity (row :: Text) <- H.tx Nothing $ H.singleEx $ [H.stmt|SHOW server_version_num|] Identity (row :: Text) <- H.tx Nothing $ H.singleEx [H.stmt|SHOW server_version_num|]
return $ read (cs row) >= minimumPgVersion return $ read (cs row) >= minimumPgVersion
hasqlError :: PgError -> IO a
hasqlError = error . cs . encodePretty
main :: IO () main :: IO ()
main = do main = do
hSetBuffering stdout LineBuffering hSetBuffering stdout LineBuffering
@@ -50,11 +52,7 @@ main = do
Prelude.putStrLn $ "Listening on port " ++ Prelude.putStrLn $ "Listening on port " ++
(show $ configPort conf :: String) (show $ configPort conf :: String)
let pgSettings = P.ParamSettings (cs $ configDbHost conf) let pgSettings = P.StringSettings $ cs (configDatabase conf)
(fromIntegral $ configDbPort conf)
(cs $ configDbUser conf)
(cs $ configDbPass conf)
(cs $ configDbName conf)
appSettings = setPort port appSettings = setPort port
. setServerName (cs $ "postgrest/" <> prettyVersion) . setServerName (cs $ "postgrest/" <> prettyVersion)
$ defaultSettings $ defaultSettings
@@ -65,12 +63,20 @@ main = do
pool :: H.Pool P.Postgres <- H.acquirePool pgSettings poolSettings pool :: H.Pool P.Postgres <- H.acquirePool pgSettings poolSettings
supportedOrError <- H.session pool isServerVersionSupported supportedOrError <- H.session pool isServerVersionSupported
either (fail . show) either hasqlError
(\supported -> (\supported ->
unless supported $ unless supported $
fail "Cannot run in this PostgreSQL version, PostgREST needs at least 9.2.0" error (
"Cannot run in this PostgreSQL version, PostgREST needs at least "
<> show minimumPgVersion)
) supportedOrError ) supportedOrError
roleOrError <- H.session pool $ do
Identity (role :: Text) <- H.tx Nothing $ H.singleEx
[H.stmt|SELECT SESSION_USER|]
return role
authenticator <- either hasqlError return roleOrError
let txSettings = Just (H.ReadCommitted, Just True) let txSettings = Just (H.ReadCommitted, Just True)
metadata <- H.session pool $ H.tx txSettings $ do metadata <- H.session pool $ H.tx txSettings $ do
tabs <- allTables tabs <- allTables
@@ -79,19 +85,18 @@ main = do
keys <- allPrimaryKeys keys <- allPrimaryKeys
return (tabs, rels, cols, keys) return (tabs, rels, cols, keys)
dbstructure <- case metadata of dbstructure <- either hasqlError
Left e -> fail $ show e (\(tabs, rels, cols, keys) ->
Right (tabs, rels, cols, keys) ->
return DbStructure { return DbStructure {
tables=tabs tables=tabs
, columns=cols , columns=cols
, relations=rels , relations=rels
, primaryKeys=keys , primaryKeys=keys
} }
) metadata
runSettings appSettings $ middle $ \ req respond -> do runSettings appSettings $ middle $ \ req respond -> do
body <- strictRequestBody req body <- strictRequestBody req
resOrError <- liftIO $ H.session pool $ H.tx txSettings $ resOrError <- liftIO $ H.session pool $ H.tx txSettings $
authenticated conf (app dbstructure conf body) req authenticated conf authenticator (app dbstructure conf authenticator body) req
either (respond . errResponse) respond resOrError either (respond . errResponse) respond resOrError
+4 -5
View File
@@ -33,22 +33,21 @@ import PostgREST.Config (AppConfig (..), corsPolicy)
import Prelude import Prelude
authenticated :: forall s. AppConfig -> authenticated :: forall s. AppConfig -> DbRole ->
(DbRole -> Request -> H.Tx P.Postgres s Response) -> (DbRole -> Request -> H.Tx P.Postgres s Response) ->
Request -> H.Tx P.Postgres s Response Request -> H.Tx P.Postgres s Response
authenticated conf app req = do authenticated conf authenticator app req = do
attempt <- httpRequesterRole (requestHeaders req) attempt <- httpRequesterRole (requestHeaders req)
case attempt of case attempt of
MalformedAuth -> MalformedAuth ->
return $ responseLBS status400 [] "Malformed basic auth header" return $ responseLBS status400 [] "Malformed basic auth header"
LoginFailed -> LoginFailed ->
return $ responseLBS status401 [] "Invalid username or password" return $ responseLBS status401 [] "Invalid username or password"
LoginSuccess role uid -> if role /= currentRole then runInRole role uid else app currentRole req LoginSuccess role uid -> if role /= authenticator then runInRole role uid else app authenticator req
NoCredentials -> if anon /= currentRole then runInRole anon "" else app currentRole req NoCredentials -> if anon /= authenticator then runInRole anon "" else app authenticator req
where where
jwtSecret = cs $ configJwtSecret conf jwtSecret = cs $ configJwtSecret conf
currentRole = cs $ configDbUser conf
anon = cs $ configAnonRole conf anon = cs $ configAnonRole conf
httpRequesterRole :: RequestHeaders -> H.Tx P.Postgres s LoginAttempt httpRequesterRole :: RequestHeaders -> H.Tx P.Postgres s LoginAttempt
httpRequesterRole hdrs = do httpRequesterRole hdrs = do
+39 -39
View File
@@ -14,28 +14,28 @@ spec = around withApp $ do
it "lists views in schema" $ it "lists views in schema" $
request methodGet "/" [] "" request methodGet "/" [] ""
`shouldRespondWith` [json| [ `shouldRespondWith` [json| [
{"schema":"1","name":"auto_incrementing_pk","insertable":true} {"schema":"test","name":"auto_incrementing_pk","insertable":true}
, {"schema":"1","name":"clients","insertable":true} , {"schema":"test","name":"clients","insertable":true}
, {"schema":"1","name":"comments","insertable":true} , {"schema":"test","name":"comments","insertable":true}
, {"schema":"1","name":"complex_items","insertable":true} , {"schema":"test","name":"complex_items","insertable":true}
, {"schema":"1","name":"compound_pk","insertable":true} , {"schema":"test","name":"compound_pk","insertable":true}
, {"schema":"1","name":"has_count_column","insertable":false} , {"schema":"test","name":"has_count_column","insertable":false}
, {"schema":"1","name":"has_fk","insertable":true} , {"schema":"test","name":"has_fk","insertable":true}
, {"schema":"1","name":"insertable_view_with_join","insertable":true} , {"schema":"test","name":"insertable_view_with_join","insertable":true}
, {"schema":"1","name":"items","insertable":true} , {"schema":"test","name":"items","insertable":true}
, {"schema":"1","name":"json","insertable":true} , {"schema":"test","name":"json","insertable":true}
, {"schema":"1","name":"materialized_view","insertable":false} , {"schema":"test","name":"materialized_view","insertable":false}
, {"schema":"1","name":"menagerie","insertable":true} , {"schema":"test","name":"menagerie","insertable":true}
, {"schema":"1","name":"no_pk","insertable":true} , {"schema":"test","name":"no_pk","insertable":true}
, {"schema":"1","name":"nullable_integer","insertable":true} , {"schema":"test","name":"nullable_integer","insertable":true}
, {"schema":"1","name":"projects","insertable":true} , {"schema":"test","name":"projects","insertable":true}
, {"schema":"1","name":"projects_view","insertable":true} , {"schema":"test","name":"projects_view","insertable":true}
, {"schema":"1","name":"simple_pk","insertable":true} , {"schema":"test","name":"simple_pk","insertable":true}
, {"schema":"1","name":"tasks","insertable":true} , {"schema":"test","name":"tasks","insertable":true}
, {"schema":"1","name":"tsearch","insertable":true} , {"schema":"test","name":"tsearch","insertable":true}
, {"schema":"1","name":"users","insertable":true} , {"schema":"test","name":"users","insertable":true}
, {"schema":"1","name":"users_projects","insertable":true} , {"schema":"test","name":"users_projects","insertable":true}
, {"schema":"1","name":"users_tasks","insertable":true} , {"schema":"test","name":"users_tasks","insertable":true}
] |] ] |]
{matchStatus = 200} {matchStatus = 200}
@@ -45,7 +45,7 @@ spec = around withApp $ do
request methodGet "/" [auth] "" request methodGet "/" [auth] ""
`shouldRespondWith` [json| [ `shouldRespondWith` [json| [
{"schema":"1","name":"authors_only","insertable":true} {"schema":"test","name":"authors_only","insertable":true}
] |] ] |]
{matchStatus = 200} {matchStatus = 200}
@@ -61,7 +61,7 @@ spec = around withApp $ do
"default": null, "default": null,
"precision": 32, "precision": 32,
"updatable": true, "updatable": true,
"schema": "1", "schema": "test",
"name": "integer", "name": "integer",
"type": "integer", "type": "integer",
"maxLen": null, "maxLen": null,
@@ -74,7 +74,7 @@ spec = around withApp $ do
"default": null, "default": null,
"precision": 53, "precision": 53,
"updatable": true, "updatable": true,
"schema": "1", "schema": "test",
"name": "double", "name": "double",
"type": "double precision", "type": "double precision",
"maxLen": null, "maxLen": null,
@@ -86,7 +86,7 @@ spec = around withApp $ do
"default": null, "default": null,
"precision": null, "precision": null,
"updatable": true, "updatable": true,
"schema": "1", "schema": "test",
"name": "varchar", "name": "varchar",
"type": "character varying", "type": "character varying",
"maxLen": null, "maxLen": null,
@@ -99,7 +99,7 @@ spec = around withApp $ do
"default": null, "default": null,
"precision": null, "precision": null,
"updatable": true, "updatable": true,
"schema": "1", "schema": "test",
"name": "boolean", "name": "boolean",
"type": "boolean", "type": "boolean",
"maxLen": null, "maxLen": null,
@@ -111,7 +111,7 @@ spec = around withApp $ do
"default": null, "default": null,
"precision": null, "precision": null,
"updatable": true, "updatable": true,
"schema": "1", "schema": "test",
"name": "date", "name": "date",
"type": "date", "type": "date",
"maxLen": null, "maxLen": null,
@@ -123,7 +123,7 @@ spec = around withApp $ do
"default": null, "default": null,
"precision": null, "precision": null,
"updatable": true, "updatable": true,
"schema": "1", "schema": "test",
"name": "money", "name": "money",
"type": "money", "type": "money",
"maxLen": null, "maxLen": null,
@@ -136,7 +136,7 @@ spec = around withApp $ do
"default": null, "default": null,
"precision": null, "precision": null,
"updatable": true, "updatable": true,
"schema": "1", "schema": "test",
"name": "enum", "name": "enum",
"type": "USER-DEFINED", "type": "USER-DEFINED",
"maxLen": null, "maxLen": null,
@@ -166,7 +166,7 @@ spec = around withApp $ do
"default":null, "default":null,
"precision":64, "precision":64,
"updatable":false, "updatable":false,
"schema":"1", "schema":"test",
"name":"id", "name":"id",
"type":"bigint", "type":"bigint",
"maxLen":null, "maxLen":null,
@@ -182,7 +182,7 @@ spec = around withApp $ do
"default":null, "default":null,
"precision":32, "precision":32,
"updatable":false, "updatable":false,
"schema":"1", "schema":"test",
"name":"auto_inc_fk", "name":"auto_inc_fk",
"type":"integer", "type":"integer",
"maxLen":null, "maxLen":null,
@@ -198,7 +198,7 @@ spec = around withApp $ do
"default":null, "default":null,
"precision":null, "precision":null,
"updatable":false, "updatable":false,
"schema":"1", "schema":"test",
"name":"simple_fk", "name":"simple_fk",
"type":"character varying", "type":"character varying",
"maxLen":255, "maxLen":255,
@@ -211,7 +211,7 @@ spec = around withApp $ do
"default":null, "default":null,
"precision":null, "precision":null,
"updatable":false, "updatable":false,
"schema":"1", "schema":"test",
"name":"nullable_string", "name":"nullable_string",
"type":"character varying", "type":"character varying",
"maxLen":null, "maxLen":null,
@@ -224,7 +224,7 @@ spec = around withApp $ do
"default":null, "default":null,
"precision":null, "precision":null,
"updatable":false, "updatable":false,
"schema":"1", "schema":"test",
"name":"non_nullable_string", "name":"non_nullable_string",
"type":"character varying", "type":"character varying",
"maxLen":null, "maxLen":null,
@@ -237,7 +237,7 @@ spec = around withApp $ do
"default":null, "default":null,
"precision":null, "precision":null,
"updatable":false, "updatable":false,
"schema":"1", "schema":"test",
"name":"inserted_at", "name":"inserted_at",
"type":"timestamp with time zone", "type":"timestamp with time zone",
"maxLen":null, "maxLen":null,
@@ -261,7 +261,7 @@ spec = around withApp $ do
"default": "nextval('\"1\".has_fk_id_seq'::regclass)", "default": "nextval('\"1\".has_fk_id_seq'::regclass)",
"precision": 64, "precision": 64,
"updatable": true, "updatable": true,
"schema": "1", "schema": "test",
"name": "id", "name": "id",
"type": "bigint", "type": "bigint",
"maxLen": null, "maxLen": null,
@@ -273,7 +273,7 @@ spec = around withApp $ do
"default": null, "default": null,
"precision": 32, "precision": 32,
"updatable": true, "updatable": true,
"schema": "1", "schema": "test",
"name": "auto_inc_fk", "name": "auto_inc_fk",
"type": "integer", "type": "integer",
"maxLen": null, "maxLen": null,
@@ -285,7 +285,7 @@ spec = around withApp $ do
"default": null, "default": null,
"precision": null, "precision": null,
"updatable": true, "updatable": true,
"schema": "1", "schema": "test",
"name": "simple_fk", "name": "simple_fk",
"type": "character varying", "type": "character varying",
"maxLen": 255, "maxLen": 255,
+23 -19
View File
@@ -20,6 +20,7 @@ import Network.HTTP.Types.Header (Header, ByteRange, renderByteRange,
import Codec.Binary.Base64.String (encode) import Codec.Binary.Base64.String (encode)
import Data.CaseInsensitive (CI(..)) import Data.CaseInsensitive (CI(..))
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Data.Functor.Identity
import Text.Regex.TDFA ((=~)) import Text.Regex.TDFA ((=~))
import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Char8 as BS
import System.Process (readProcess) import System.Process (readProcess)
@@ -33,28 +34,31 @@ import PostgREST.Error(errResponse)
import PostgREST.PgStructure import PostgREST.PgStructure
import PostgREST.Types import PostgREST.Types
dbString :: String
dbString = "postgres://postgrest_test@localhost:5432/postgrest_test"
isLeft :: Either a b -> Bool isLeft :: Either a b -> Bool
isLeft (Left _ ) = True isLeft (Left _ ) = True
isLeft _ = False isLeft _ = False
cfg :: AppConfig cfg :: AppConfig
cfg = AppConfig "postgrest_test" 5432 "postgrest_test" "" "localhost" 3000 "postgrest_anonymous" False 10 "1" "safe" cfg = AppConfig dbString 3000 "postgrest_anonymous" "test" False "safe" 10
testPoolOpts :: PoolSettings testPoolOpts :: PoolSettings
testPoolOpts = fromMaybe (error "bad settings") $ H.poolSettings 1 30 testPoolOpts = fromMaybe (error "bad settings") $ H.poolSettings 1 30
pgSettings :: P.Settings pgSettings :: P.Settings
pgSettings = P.ParamSettings (cs $ configDbHost cfg) pgSettings = P.StringSettings $ cs dbString
(fromIntegral $ configDbPort cfg)
(cs $ configDbUser cfg)
(cs $ configDbPass cfg)
(cs $ configDbName cfg)
withApp :: ActionWith Application -> IO () withApp :: ActionWith Application -> IO ()
withApp perform = do withApp perform = do
pool :: H.Pool P.Postgres pool :: H.Pool P.Postgres
<- H.acquirePool pgSettings testPoolOpts <- H.acquirePool pgSettings testPoolOpts
Right authenticator <- H.session pool $ do
Identity (role :: Text) <- H.tx Nothing $ H.singleEx [H.stmt|SELECT SESSION_USER|]
return role
let txSettings = Just (H.ReadCommitted, Just True) let txSettings = Just (H.ReadCommitted, Just True)
metadata <- H.session pool $ H.tx txSettings $ do metadata <- H.session pool $ H.tx txSettings $ do
tabs <- allTables tabs <- allTables
@@ -66,7 +70,7 @@ withApp perform = do
dbstructure <- case metadata of dbstructure <- case metadata of
Left e -> fail $ show e Left e -> fail $ show e
Right (tabs, rels, cols, keys) -> Right (tabs, rels, cols, keys) ->
return $ DbStructure { return DbStructure {
tables=tabs tables=tabs
, columns=cols , columns=cols
, relations=rels , relations=rels
@@ -76,7 +80,7 @@ withApp perform = do
perform $ middle $ \req resp -> do perform $ middle $ \req resp -> do
body <- strictRequestBody req body <- strictRequestBody req
result <- liftIO $ H.session pool $ H.tx txSettings result <- liftIO $ H.session pool $ H.tx txSettings
$ authenticated cfg (app dbstructure cfg body) req $ authenticated cfg authenticator (app dbstructure cfg authenticator body) req
either (resp . errResponse) resp result either (resp . errResponse) resp result
where middle = defaultMiddle False where middle = defaultMiddle False
@@ -88,7 +92,7 @@ resetDb = do
<- H.acquirePool pgSettings testPoolOpts <- H.acquirePool pgSettings testPoolOpts
void . liftIO $ H.session pool $ void . liftIO $ H.session pool $
H.tx Nothing $ do H.tx Nothing $ do
H.unitEx [H.stmt| drop schema if exists "1" cascade |] H.unitEx [H.stmt| drop schema if exists test cascade |]
H.unitEx [H.stmt| drop schema if exists private cascade |] H.unitEx [H.stmt| drop schema if exists private cascade |]
H.unitEx [H.stmt| drop schema if exists postgrest cascade |] H.unitEx [H.stmt| drop schema if exists postgrest cascade |]
@@ -129,7 +133,7 @@ clearTable :: Text -> IO ()
clearTable table = do clearTable table = do
pool <- testPool pool <- testPool
void . liftIO $ H.session pool $ H.tx Nothing $ void . liftIO $ H.session pool $ H.tx Nothing $
H.unitEx $ B.Stmt ("delete from \"1\"."<>table) V.empty True H.unitEx $ B.Stmt ("delete from test."<>table) V.empty True
createItems :: Int -> IO () createItems :: Int -> IO ()
createItems n = do createItems n = do
@@ -137,7 +141,7 @@ createItems n = do
void . liftIO $ H.session pool $ H.tx Nothing txn void . liftIO $ H.session pool $ H.tx Nothing txn
where where
txn = mapM_ H.unitEx stmts txn = mapM_ H.unitEx stmts
stmts = map [H.stmt|insert into "1".items (id) values (?)|] [1..n] stmts = map [H.stmt|insert into test.items (id) values (?)|] [1..n]
createComplexItems :: IO () createComplexItems :: IO ()
createComplexItems = do createComplexItems = do
@@ -145,11 +149,11 @@ createComplexItems = do
void . liftIO $ H.session pool $ H.tx Nothing txn void . liftIO $ H.session pool $ H.tx Nothing txn
where where
txn = mapM_ H.unitEx stmts txn = mapM_ H.unitEx stmts
stmts = getZipList $ [H.stmt|insert into "1".complex_items (id, name, settings) values (?,?,?)|] stmts = getZipList $ [H.stmt|insert into test.complex_items (id, name, settings) values (?,?,?)|]
<$> ZipList ([1..3]::[Int]) <$> ZipList ([1..3]::[Int])
<*> ZipList (["One", "Two", "Three"]::[Text]) <*> ZipList (["One", "Two", "Three"]::[Text])
<*> ZipList ([jobj,jobj,jobj]) <*> ZipList [jobj,jobj,jobj]
jobj = (J.object [("foo", J.object [("int", J.Number 1),("bar", J.String "baz")])]) jobj = J.object [("foo", J.object [("int", J.Number 1),("bar", J.String "baz")])]
createNulls :: Int -> IO () createNulls :: Int -> IO ()
createNulls n = do createNulls n = do
@@ -157,14 +161,14 @@ createNulls n = do
void . liftIO $ H.session pool $ H.tx Nothing txn void . liftIO $ H.session pool $ H.tx Nothing txn
where where
txn = mapM_ H.unitEx (stmt':stmts) txn = mapM_ H.unitEx (stmt':stmts)
stmt' = [H.stmt|insert into "1".no_pk (a,b) values (null,null)|] stmt' = [H.stmt|insert into test.no_pk (a,b) values (null,null)|]
stmts = map [H.stmt|insert into "1".no_pk (a,b) values (?,0)|] [1..n] stmts = map [H.stmt|insert into test.no_pk (a,b) values (?,0)|] [1..n]
createNullInteger :: IO () createNullInteger :: IO ()
createNullInteger = do createNullInteger = do
pool <- testPool pool <- testPool
void . liftIO $ H.session pool $ H.tx Nothing $ void . liftIO $ H.session pool $ H.tx Nothing $
H.unitEx $ [H.stmt| insert into "1".nullable_integer (a) values (null) |] H.unitEx $ [H.stmt| insert into "test".nullable_integer (a) values (null) |]
createLikableStrings :: IO () createLikableStrings :: IO ()
createLikableStrings = do createLikableStrings = do
@@ -174,7 +178,7 @@ createLikableStrings = do
H.unitEx $ insertSimplePk "xYYx" "v" H.unitEx $ insertSimplePk "xYYx" "v"
where where
insertSimplePk :: Text -> Text -> H.Stmt P.Postgres insertSimplePk :: Text -> Text -> H.Stmt P.Postgres
insertSimplePk = [H.stmt|insert into "1".simple_pk (k, extra) values (?,?)|] insertSimplePk = [H.stmt|insert into test.simple_pk (k, extra) values (?,?)|]
createJsonData :: IO () createJsonData :: IO ()
createJsonData = do createJsonData = do
@@ -182,6 +186,6 @@ createJsonData = do
void . liftIO $ H.session pool $ H.tx Nothing $ void . liftIO $ H.session pool $ H.tx Nothing $
H.unitEx $ H.unitEx $
[H.stmt| [H.stmt|
insert into "1".json (data) values (?) insert into test.json (data) values (?)
|] |]
(J.object [("foo", J.object [("bar", J.String "baz")])]) (J.object [("foo", J.object [("bar", J.String "baz")])])
+5 -5
View File
@@ -32,7 +32,7 @@ spec = around dbWithSchema $ do
describe "insert" $ describe "insert" $
describe "with an auto-increment key" $ do describe "with an auto-increment key" $ do
it "inserts and responds with a full object description" $ \conn -> do it "inserts and responds with a full object description" $ \conn -> do
r <- insert "1" "auto_incrementing_pk" (SqlRow [ r <- insert "test" "auto_incrementing_pk" (SqlRow [
("non_nullable_string", toSql ("a string"::String))]) conn ("non_nullable_string", toSql ("a string"::String))]) conn
let returnRow = incFromList . toList $ r let returnRow = incFromList . toList $ r
incStr returnRow `shouldBe` "a string" incStr returnRow `shouldBe` "a string"
@@ -43,19 +43,19 @@ spec = around dbWithSchema $ do
[returnRow] `shouldBe` map incFromList tRows [returnRow] `shouldBe` map incFromList tRows
it "throws an exception if the PK is not unique" $ \conn -> do it "throws an exception if the PK is not unique" $ \conn -> do
r <- insert "1" "auto_incrementing_pk" (SqlRow [ r <- insert "test" "auto_incrementing_pk" (SqlRow [
("non_nullable_string", toSql ("a string"::String))]) conn ("non_nullable_string", toSql ("a string"::String))]) conn
let row = SqlRow . map (Control.Arrow.first cs) . toList $ r let row = SqlRow . map (Control.Arrow.first cs) . toList $ r
insert "1" "auto_incrementing_pk" row conn `shouldThrow` \e -> insert "test" "auto_incrementing_pk" row conn `shouldThrow` \e ->
seState e == "23505" -- uniqueness violation code seState e == "23505" -- uniqueness violation code
it "throws an exception if a required value is missing" $ \conn -> it "throws an exception if a required value is missing" $ \conn ->
insert "1" "auto_incrementing_pk" (SqlRow [ insert "test" "auto_incrementing_pk" (SqlRow [
("nullable_string", toSql ("a string"::String))]) conn ("nullable_string", toSql ("a string"::String))]) conn
`shouldThrow` \e -> seState e == "23502" `shouldThrow` \e -> seState e == "23502"
it "generates a default values query if no data is provided" $ \c -> do it "generates a default values query if no data is provided" $ \c -> do
r <- insert "1" "items" (SqlRow []) c r <- insert "test" "items" (SqlRow []) c
let [row] = toList r let [row] = toList r
quickALQuery c "select * from \"1\".items where id = ?" [snd row] quickALQuery c "select * from \"1\".items where id = ?" [snd row]
`shouldReturn` [[row]] `shouldReturn` [[row]]
+4 -4
View File
@@ -12,25 +12,25 @@ spec :: Spec
spec = around dbWithSchema $ beforeWith setRole $ do spec = around dbWithSchema $ beforeWith setRole $ do
describe "tables" $ describe "tables" $
it "shows all the tables" $ \conn -> do it "shows all the tables" $ \conn -> do
ts <- tables "1" conn ts <- tables "test" conn
map tableName ts `shouldBe` ["authors_only","auto_incrementing_pk", map tableName ts `shouldBe` ["authors_only","auto_incrementing_pk",
"compound_pk","has_fk","insertable_view_with_join","items","menagerie","no_pk", "simple_pk"] "compound_pk","has_fk","insertable_view_with_join","items","menagerie","no_pk", "simple_pk"]
describe "columns" $ do describe "columns" $ do
it "responds with each column for the table" $ \conn -> do it "responds with each column for the table" $ \conn -> do
cs <- columns "1" "auto_incrementing_pk" conn cs <- columns "test" "auto_incrementing_pk" conn
map colName cs `shouldBe` ["id","nullable_string","non_nullable_string", map colName cs `shouldBe` ["id","nullable_string","non_nullable_string",
"inserted_at"] "inserted_at"]
it "includes foreign key data" $ \conn -> do it "includes foreign key data" $ \conn -> do
cs <- columns "1" "has_fk" conn cs <- columns "test" "has_fk" conn
map colFK cs `shouldBe` [Nothing, map colFK cs `shouldBe` [Nothing,
Just $ ForeignKey "auto_incrementing_pk" "id", Just $ ForeignKey "auto_incrementing_pk" "id",
Just $ ForeignKey "simple_pk" "k"] Just $ ForeignKey "simple_pk" "k"]
describe "foreignKeys" $ describe "foreignKeys" $
it "has a description of the foreign key columns" $ \conn -> it "has a description of the foreign key columns" $ \conn ->
foreignKeys "1" "has_fk" conn `shouldReturn` M.fromList [ foreignKeys "test" "has_fk" conn `shouldReturn` M.fromList [
("auto_inc_fk", ForeignKey {fkTable="auto_incrementing_pk", fkCol="id"}), ("auto_inc_fk", ForeignKey {fkTable="auto_incrementing_pk", fkCol="id"}),
("simple_fk", ForeignKey { fkTable="simple_pk", fkCol="k"})] ("simple_fk", ForeignKey { fkTable="simple_pk", fkCol="k"})]
+58 -58
View File
@@ -5,10 +5,10 @@ SET check_function_bodies = false;
SET client_min_messages = warning; SET client_min_messages = warning;
CREATE SCHEMA "1"; CREATE SCHEMA test;
ALTER SCHEMA "1" OWNER TO postgrest_test; ALTER SCHEMA test OWNER TO postgrest_test;
CREATE SCHEMA postgrest; CREATE SCHEMA postgrest;
@@ -30,7 +30,7 @@ CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
SET search_path = "1", pg_catalog; SET search_path = test, pg_catalog;
CREATE TYPE enum_menagerie_type AS ENUM ( CREATE TYPE enum_menagerie_type AS ENUM (
@@ -39,7 +39,7 @@ CREATE TYPE enum_menagerie_type AS ENUM (
); );
ALTER TYPE "1".enum_menagerie_type OWNER TO postgrest_test; ALTER TYPE test.enum_menagerie_type OWNER TO postgrest_test;
SET search_path = postgrest, pg_catalog; SET search_path = postgrest, pg_catalog;
@@ -83,18 +83,18 @@ $$;
ALTER FUNCTION postgrest.set_authors_only_owner() OWNER TO postgrest_test; ALTER FUNCTION postgrest.set_authors_only_owner() OWNER TO postgrest_test;
CREATE FUNCTION "1".insert_insertable_view_with_join() RETURNS trigger CREATE FUNCTION test.insert_insertable_view_with_join() RETURNS trigger
LANGUAGE plpgsql LANGUAGE plpgsql
AS $$ AS $$
begin begin
INSERT INTO "1".auto_incrementing_pk (nullable_string, non_nullable_string) VALUES (NEW.nullable_string, NEW.non_nullable_string); INSERT INTO test.auto_incrementing_pk (nullable_string, non_nullable_string) VALUES (NEW.nullable_string, NEW.non_nullable_string);
RETURN NEW; RETURN NEW;
end; end;
$$; $$;
ALTER FUNCTION "1".insert_insertable_view_with_join() OWNER TO postgrest_test; ALTER FUNCTION test.insert_insertable_view_with_join() OWNER TO postgrest_test;
SET search_path = "1", pg_catalog; SET search_path = test, pg_catalog;
SET default_tablespace = ''; SET default_tablespace = '';
@@ -107,7 +107,7 @@ CREATE TABLE authors_only (
); );
ALTER TABLE "1".authors_only OWNER TO postgrest_test_author; ALTER TABLE test.authors_only OWNER TO postgrest_test_author;
CREATE TABLE auto_incrementing_pk ( CREATE TABLE auto_incrementing_pk (
@@ -118,7 +118,7 @@ CREATE TABLE auto_incrementing_pk (
); );
ALTER TABLE "1".auto_incrementing_pk OWNER TO postgrest_test; ALTER TABLE test.auto_incrementing_pk OWNER TO postgrest_test;
CREATE SEQUENCE auto_incrementing_pk_id_seq CREATE SEQUENCE auto_incrementing_pk_id_seq
@@ -129,7 +129,7 @@ CREATE SEQUENCE auto_incrementing_pk_id_seq
CACHE 1; CACHE 1;
ALTER TABLE "1".auto_incrementing_pk_id_seq OWNER TO postgrest_test; ALTER TABLE test.auto_incrementing_pk_id_seq OWNER TO postgrest_test;
ALTER SEQUENCE auto_incrementing_pk_id_seq OWNED BY auto_incrementing_pk.id; ALTER SEQUENCE auto_incrementing_pk_id_seq OWNED BY auto_incrementing_pk.id;
@@ -143,7 +143,7 @@ CREATE TABLE compound_pk (
); );
ALTER TABLE "1".compound_pk OWNER TO postgrest_test; ALTER TABLE test.compound_pk OWNER TO postgrest_test;
CREATE TABLE has_fk ( CREATE TABLE has_fk (
@@ -153,7 +153,7 @@ CREATE TABLE has_fk (
); );
ALTER TABLE "1".has_fk OWNER TO postgrest_test; ALTER TABLE test.has_fk OWNER TO postgrest_test;
CREATE SEQUENCE has_fk_id_seq CREATE SEQUENCE has_fk_id_seq
@@ -164,18 +164,18 @@ CREATE SEQUENCE has_fk_id_seq
CACHE 1; CACHE 1;
ALTER TABLE "1".has_fk_id_seq OWNER TO postgrest_test; ALTER TABLE test.has_fk_id_seq OWNER TO postgrest_test;
ALTER SEQUENCE has_fk_id_seq OWNED BY has_fk.id; ALTER SEQUENCE has_fk_id_seq OWNED BY has_fk.id;
CREATE MATERIALIZED VIEW "1".materialized_view AS CREATE MATERIALIZED VIEW test.materialized_view AS
SELECT SELECT
version(); version();
ALTER TABLE "1".materialized_view OWNER TO postgrest_test; ALTER TABLE test.materialized_view OWNER TO postgrest_test;
CREATE VIEW "1".insertable_view_with_join AS CREATE VIEW test.insertable_view_with_join AS
SELECT has_fk.id, SELECT has_fk.id,
has_fk.auto_inc_fk, has_fk.auto_inc_fk,
has_fk.simple_fk, has_fk.simple_fk,
@@ -186,12 +186,12 @@ CREATE VIEW "1".insertable_view_with_join AS
JOIN auto_incrementing_pk USING (id)); JOIN auto_incrementing_pk USING (id));
ALTER TABLE "1".insertable_view_with_join OWNER TO postgrest_test; ALTER TABLE test.insertable_view_with_join OWNER TO postgrest_test;
CREATE VIEW "1".has_count_column AS CREATE VIEW test.has_count_column AS
SELECT 1 AS count; SELECT 1 AS count;
ALTER TABLE "1".insertable_view_with_join OWNER TO postgrest_test; ALTER TABLE test.insertable_view_with_join OWNER TO postgrest_test;
CREATE TABLE items ( CREATE TABLE items (
@@ -199,7 +199,7 @@ CREATE TABLE items (
); );
ALTER TABLE "1".items OWNER TO postgrest_test; ALTER TABLE test.items OWNER TO postgrest_test;
CREATE TABLE complex_items ( CREATE TABLE complex_items (
id bigint NOT NULL, id bigint NOT NULL,
@@ -208,41 +208,41 @@ CREATE TABLE complex_items (
); );
ALTER TABLE "1".complex_items OWNER TO postgrest_test; ALTER TABLE test.complex_items OWNER TO postgrest_test;
--- Structure for testing table relations --- Structure for testing table relations
CREATE TABLE clients( CREATE TABLE clients(
id INT PRIMARY KEY NOT NULL, id INT PRIMARY KEY NOT NULL,
name TEXT NOT NULL name TEXT NOT NULL
); );
ALTER TABLE "1".clients OWNER TO postgrest_test; ALTER TABLE test.clients OWNER TO postgrest_test;
CREATE TABLE projects( CREATE TABLE projects(
id INT PRIMARY KEY NOT NULL, id INT PRIMARY KEY NOT NULL,
name TEXT NOT NULL, name TEXT NOT NULL,
client_id INT REFERENCES clients(id) client_id INT REFERENCES clients(id)
); );
ALTER TABLE "1".projects OWNER TO postgrest_test; ALTER TABLE test.projects OWNER TO postgrest_test;
CREATE TABLE tasks( CREATE TABLE tasks(
id INT PRIMARY KEY NOT NULL, id INT PRIMARY KEY NOT NULL,
name TEXT NOT NULL, name TEXT NOT NULL,
project_id INT REFERENCES projects(id) project_id INT REFERENCES projects(id)
); );
ALTER TABLE "1".tasks OWNER TO postgrest_test; ALTER TABLE test.tasks OWNER TO postgrest_test;
CREATE TABLE users( CREATE TABLE users(
id INT PRIMARY KEY NOT NULL, id INT PRIMARY KEY NOT NULL,
name TEXT NOT NULL name TEXT NOT NULL
); );
ALTER TABLE "1".users OWNER TO postgrest_test; ALTER TABLE test.users OWNER TO postgrest_test;
CREATE TABLE users_tasks( CREATE TABLE users_tasks(
user_id INT REFERENCES users(id), user_id INT REFERENCES users(id),
task_id INT REFERENCES tasks(id), task_id INT REFERENCES tasks(id),
CONSTRAINT task_user PRIMARY KEY (task_id,user_id) CONSTRAINT task_user PRIMARY KEY (task_id,user_id)
); );
ALTER TABLE "1".users_tasks OWNER TO postgrest_test; ALTER TABLE test.users_tasks OWNER TO postgrest_test;
CREATE TABLE comments( CREATE TABLE comments(
id INT PRIMARY KEY NOT NULL, id INT PRIMARY KEY NOT NULL,
@@ -252,22 +252,22 @@ task_id INT NOT NULL,
content TEXT NOT NULL, content TEXT NOT NULL,
FOREIGN KEY (task_id,user_id) REFERENCES users_tasks (task_id,user_id) FOREIGN KEY (task_id,user_id) REFERENCES users_tasks (task_id,user_id)
); );
ALTER TABLE "1".comments OWNER TO postgrest_test; ALTER TABLE test.comments OWNER TO postgrest_test;
CREATE TABLE users_projects( CREATE TABLE users_projects(
user_id INT REFERENCES users(id), user_id INT REFERENCES users(id),
project_id INT REFERENCES projects(id), project_id INT REFERENCES projects(id),
CONSTRAINT project_user PRIMARY KEY (project_id, user_id) CONSTRAINT project_user PRIMARY KEY (project_id, user_id)
); );
ALTER TABLE "1".users_projects OWNER TO postgrest_test; ALTER TABLE test.users_projects OWNER TO postgrest_test;
CREATE VIEW "1".projects_view AS CREATE VIEW test.projects_view AS
SELECT SELECT
projects.id, projects.id,
projects.name, projects.name,
projects.client_id projects.client_id
FROM projects; FROM projects;
ALTER TABLE "1".projects_view OWNER TO postgrest_test; ALTER TABLE test.projects_view OWNER TO postgrest_test;
------- SAMPLE DATA ----- ------- SAMPLE DATA -----
INSERT INTO clients VALUES (1, 'Microsoft'),(2, 'Apple'); INSERT INTO clients VALUES (1, 'Microsoft'),(2, 'Apple');
INSERT INTO projects VALUES (1,'Windows 7', 1),(2,'Windows 10', 1),(3,'IOS', 2),(4,'OSX', 2); INSERT INTO projects VALUES (1,'Windows 7', 1),(2,'Windows 10', 1),(3,'IOS', 2),(4,'OSX', 2);
@@ -286,25 +286,25 @@ CREATE SEQUENCE items_id_seq
CACHE 1; CACHE 1;
ALTER TABLE "1".items_id_seq OWNER TO postgrest_test; ALTER TABLE test.items_id_seq OWNER TO postgrest_test;
ALTER SEQUENCE items_id_seq OWNED BY items.id; ALTER SEQUENCE items_id_seq OWNED BY items.id;
CREATE FUNCTION "1".getitemrange(min bigint, max bigint) RETURNS SETOF "1".items AS $$ CREATE FUNCTION test.getitemrange(min bigint, max bigint) RETURNS SETOF test.items AS $$
SELECT * FROM "1".items WHERE id > $1 AND id <= $2; SELECT * FROM test.items WHERE id > $1 AND id <= $2;
$$ LANGUAGE SQL; $$ LANGUAGE SQL;
CREATE FUNCTION "1".sayhello(name text) RETURNS text AS $$ CREATE FUNCTION test.sayhello(name text) RETURNS text AS $$
SELECT 'Hello, ' || $1; SELECT 'Hello, ' || $1;
$$ LANGUAGE SQL; $$ LANGUAGE SQL;
CREATE FUNCTION "1".problem() RETURNS void LANGUAGE plpgsql AS CREATE FUNCTION test.problem() RETURNS void LANGUAGE plpgsql AS
$$ $$
BEGIN BEGIN
RAISE 'bad thing'; RAISE 'bad thing';
@@ -323,7 +323,7 @@ CREATE TABLE menagerie (
); );
ALTER TABLE "1".menagerie OWNER TO postgrest_test; ALTER TABLE test.menagerie OWNER TO postgrest_test;
CREATE TABLE no_pk ( CREATE TABLE no_pk (
@@ -332,7 +332,7 @@ CREATE TABLE no_pk (
); );
ALTER TABLE "1".no_pk OWNER TO postgrest_test; ALTER TABLE test.no_pk OWNER TO postgrest_test;
CREATE TABLE nullable_integer ( CREATE TABLE nullable_integer (
@@ -340,7 +340,7 @@ CREATE TABLE nullable_integer (
); );
ALTER TABLE "1".nullable_integer OWNER TO postgrest_test; ALTER TABLE test.nullable_integer OWNER TO postgrest_test;
CREATE TABLE simple_pk ( CREATE TABLE simple_pk (
@@ -349,7 +349,7 @@ CREATE TABLE simple_pk (
); );
ALTER TABLE "1".simple_pk OWNER TO postgrest_test; ALTER TABLE test.simple_pk OWNER TO postgrest_test;
CREATE TABLE json CREATE TABLE json
@@ -358,14 +358,14 @@ CREATE TABLE json
); );
ALTER TABLE "1".json OWNER TO postgrest_test; ALTER TABLE test.json OWNER TO postgrest_test;
CREATE TABLE tsearch ( CREATE TABLE tsearch (
text_search_vector tsvector text_search_vector tsvector
); );
ALTER TABLE "1".tsearch OWNER TO postgrest_test; ALTER TABLE test.tsearch OWNER TO postgrest_test;
SET search_path = postgrest, pg_catalog; SET search_path = postgrest, pg_catalog;
@@ -406,7 +406,7 @@ ALTER TABLE private.articles_id_seq OWNER TO postgrest_test;
ALTER SEQUENCE articles_id_seq OWNED BY articles.id; ALTER SEQUENCE articles_id_seq OWNED BY articles.id;
SET search_path = "1", pg_catalog; SET search_path = test, pg_catalog;
ALTER TABLE ONLY auto_incrementing_pk ALTER COLUMN id SET DEFAULT nextval('auto_incrementing_pk_id_seq'::regclass); ALTER TABLE ONLY auto_incrementing_pk ALTER COLUMN id SET DEFAULT nextval('auto_incrementing_pk_id_seq'::regclass);
@@ -426,7 +426,7 @@ SET search_path = private, pg_catalog;
ALTER TABLE ONLY articles ALTER COLUMN id SET DEFAULT nextval('articles_id_seq'::regclass); ALTER TABLE ONLY articles ALTER COLUMN id SET DEFAULT nextval('articles_id_seq'::regclass);
SET search_path = "1", pg_catalog; SET search_path = test, pg_catalog;
@@ -471,20 +471,20 @@ SET search_path = private, pg_catalog;
SELECT pg_catalog.setval('articles_id_seq', 1, false); SELECT pg_catalog.setval('articles_id_seq', 1, false);
SET search_path = "1", pg_catalog; SET search_path = test, pg_catalog;
CREATE FUNCTION public.always_true("1".items) RETURNS boolean CREATE FUNCTION public.always_true(test.items) RETURNS boolean
LANGUAGE sql STABLE LANGUAGE sql STABLE
AS $$ SELECT true $$; AS $$ SELECT true $$;
ALTER FUNCTION public.always_true("1".items) OWNER TO postgrest_test; ALTER FUNCTION public.always_true(test.items) OWNER TO postgrest_test;
ALTER TABLE ONLY authors_only ALTER TABLE ONLY authors_only
ADD CONSTRAINT authors_only_pkey PRIMARY KEY (secret); ADD CONSTRAINT authors_only_pkey PRIMARY KEY (secret);
CREATE TRIGGER insert_insertable_view_with_join INSTEAD OF INSERT ON "1".insertable_view_with_join FOR EACH ROW EXECUTE PROCEDURE "1".insert_insertable_view_with_join(); CREATE TRIGGER insert_insertable_view_with_join INSTEAD OF INSERT ON test.insertable_view_with_join FOR EACH ROW EXECUTE PROCEDURE test.insert_insertable_view_with_join();
CREATE TRIGGER secrets_owner_track BEFORE INSERT OR UPDATE ON authors_only FOR EACH ROW EXECUTE PROCEDURE postgrest.set_authors_only_owner(); CREATE TRIGGER secrets_owner_track BEFORE INSERT OR UPDATE ON authors_only FOR EACH ROW EXECUTE PROCEDURE postgrest.set_authors_only_owner();
@@ -547,7 +547,7 @@ SET search_path = private, pg_catalog;
CREATE TRIGGER articles_owner_track BEFORE INSERT OR UPDATE ON articles FOR EACH ROW EXECUTE PROCEDURE postgrest.update_owner(); CREATE TRIGGER articles_owner_track BEFORE INSERT OR UPDATE ON articles FOR EACH ROW EXECUTE PROCEDURE postgrest.update_owner();
SET search_path = "1", pg_catalog; SET search_path = test, pg_catalog;
ALTER TABLE ONLY has_fk ALTER TABLE ONLY has_fk
@@ -560,11 +560,11 @@ ALTER TABLE ONLY has_fk
REVOKE ALL ON SCHEMA "1" FROM PUBLIC; REVOKE ALL ON SCHEMA test FROM PUBLIC;
REVOKE ALL ON SCHEMA "1" FROM postgrest_test; REVOKE ALL ON SCHEMA test FROM postgrest_test;
GRANT ALL ON SCHEMA "1" TO postgrest_test; GRANT ALL ON SCHEMA test TO postgrest_test;
GRANT USAGE ON SCHEMA "1" TO postgrest_anonymous; GRANT USAGE ON SCHEMA test TO postgrest_anonymous;
GRANT USAGE ON SCHEMA "1" TO postgrest_test_author; GRANT USAGE ON SCHEMA test TO postgrest_test_author;
@@ -737,10 +737,10 @@ REVOKE ALL ON TABLE has_count_column FROM postgrest_test;
GRANT ALL ON TABLE has_count_column TO postgrest_test; GRANT ALL ON TABLE has_count_column TO postgrest_test;
GRANT ALL ON TABLE has_count_column TO postgrest_anonymous; GRANT ALL ON TABLE has_count_column TO postgrest_anonymous;
REVOKE ALL ON FUNCTION public.always_true("1".items) FROM PUBLIC; REVOKE ALL ON FUNCTION public.always_true(test.items) FROM PUBLIC;
REVOKE ALL ON FUNCTION public.always_true("1".items) FROM postgrest_test; REVOKE ALL ON FUNCTION public.always_true(test.items) FROM postgrest_test;
GRANT ALL ON FUNCTION public.always_true("1".items) TO postgrest_test; GRANT ALL ON FUNCTION public.always_true(test.items) TO postgrest_test;
GRANT ALL ON FUNCTION public.always_true("1".items) TO postgrest_anonymous; GRANT ALL ON FUNCTION public.always_true(test.items) TO postgrest_anonymous;
SET search_path = postgrest, pg_catalog; SET search_path = postgrest, pg_catalog;