From 3e99995e6a86959f080080623c06aaded0747703 Mon Sep 17 00:00:00 2001 From: Steve Chavez Date: Wed, 1 Mar 2023 12:23:19 -0500 Subject: [PATCH] feat: make db-root-spec stable (#2694) --- CHANGELOG.md | 2 ++ src/PostgREST/App.hs | 14 ++++++-------- src/PostgREST/AppState.hs | 11 ----------- src/PostgREST/Query.hs | 12 ++++-------- src/PostgREST/Workers.hs | 4 ---- test/spec/Feature/OpenApi/RootSpec.hs | 8 -------- test/spec/Main.hs | 6 ------ test/spec/fixtures/schema.sql | 14 +------------- 8 files changed, 13 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94ac0296f..7b58559a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - #1100, Customizable OpenAPI title - @AnthonyFisi - #2506, Add `server-trace-header` for tracing HTTP requests. - @steve-chavez + When the client sends the request header specified in the config it will be included in the response headers. + - #2694, Make `db-root-spec` stable. - @steve-chavez + + This can be used to override the OpenAPI spec with a custom database function ### Fixed diff --git a/src/PostgREST/App.hs b/src/PostgREST/App.hs index 705af6aaa..f8973f51c 100644 --- a/src/PostgREST/App.hs +++ b/src/PostgREST/App.hs @@ -111,12 +111,11 @@ postgrest conf appState connWorker = appConf <- AppState.getConfig appState -- the config must be read again because it can reload maybeSchemaCache <- AppState.getSchemaCache appState pgVer <- AppState.getPgVersion appState - jsonDbS <- AppState.getJsonDbS appState let eitherResponse :: IO (Either Error Wai.Response) eitherResponse = - runExceptT $ postgrestResponse appState appConf maybeSchemaCache jsonDbS pgVer authResult req + runExceptT $ postgrestResponse appState appConf maybeSchemaCache pgVer authResult req response <- either Error.errorResponseFor identity <$> eitherResponse -- Launch the connWorker when the connection is down. The postgrest @@ -132,12 +131,11 @@ postgrestResponse :: AppState.AppState -> AppConfig -> Maybe SchemaCache - -> ByteString -> PgVersion -> AuthResult -> Wai.Request -> Handler IO Wai.Response -postgrestResponse appState conf@AppConfig{..} maybeSchemaCache jsonDbS pgVer authResult@AuthResult{..} req = do +postgrestResponse appState conf@AppConfig{..} maybeSchemaCache pgVer authResult@AuthResult{..} req = do sCache <- case maybeSchemaCache of Just sCache -> @@ -152,7 +150,7 @@ postgrestResponse appState conf@AppConfig{..} maybeSchemaCache jsonDbS pgVer aut ApiRequest.userApiRequest conf sCache req body Response.optionalRollback conf apiRequest $ - handleRequest authResult conf appState (Just authRole /= configDbAnonRole) configDbPreparedStatements jsonDbS pgVer apiRequest sCache + handleRequest authResult conf appState (Just authRole /= configDbAnonRole) configDbPreparedStatements pgVer apiRequest sCache runDbHandler :: AppState.AppState -> SQL.Mode -> Bool -> Bool -> DbHandler b -> Handler IO b runDbHandler appState mode authenticated prepared handler = do @@ -170,8 +168,8 @@ runDbHandler appState mode authenticated prepared handler = do liftEither resp -handleRequest :: AuthResult -> AppConfig -> AppState.AppState -> Bool -> Bool -> ByteString -> PgVersion -> ApiRequest -> SchemaCache -> Handler IO Wai.Response -handleRequest AuthResult{..} conf appState authenticated prepared jsonDbS pgVer apiReq@ApiRequest{..} sCache = +handleRequest :: AuthResult -> AppConfig -> AppState.AppState -> Bool -> Bool -> PgVersion -> ApiRequest -> SchemaCache -> Handler IO Wai.Response +handleRequest AuthResult{..} conf appState authenticated prepared pgVer apiReq@ApiRequest{..} sCache = case (iAction, iTarget) of (ActionRead headersOnly, TargetIdent identifier) -> do rPlan <- liftEither $ Plan.readPlan identifier conf sCache apiReq @@ -223,6 +221,6 @@ handleRequest AuthResult{..} conf appState authenticated prepared jsonDbS pgVer where runQuery mode query = runDbHandler appState mode authenticated prepared $ do - Query.setPgLocals conf authClaims authRole apiReq jsonDbS pgVer + Query.setPgLocals conf authClaims authRole apiReq pgVer Query.runPreReq conf query diff --git a/src/PostgREST/AppState.hs b/src/PostgREST/AppState.hs index 390c5815f..1a36a1864 100644 --- a/src/PostgREST/AppState.hs +++ b/src/PostgREST/AppState.hs @@ -7,7 +7,6 @@ module PostgREST.AppState , getConfig , getSchemaCache , getIsListenerOn - , getJsonDbS , getMainThreadId , getPgVersion , getRetryNextIn @@ -20,7 +19,6 @@ module PostgREST.AppState , putConfig , putSchemaCache , putIsListenerOn - , putJsonDbS , putPgVersion , putRetryNextIn , signalListener @@ -58,8 +56,6 @@ data AppState = AppState , statePgVersion :: IORef PgVersion -- | No schema cache at the start. Will be filled in by the connectionWorker , stateSchemaCache :: IORef (Maybe SchemaCache) - -- | Cached SchemaCache in json - , stateJsonDbS :: IORef ByteString -- | Binary semaphore to make sure just one connectionWorker can run at a time , stateWorkerSem :: MVar () -- | Binary semaphore used to sync the listener(NOTIFY reload) with the connectionWorker. @@ -90,7 +86,6 @@ initWithPool pool conf = do appState <- AppState pool <$> newIORef minimumPgVersion -- assume we're in a supported version when starting, this will be corrected on a later step <*> newIORef Nothing - <*> newIORef mempty <*> newEmptyMVar <*> newEmptyMVar <*> newIORef False @@ -146,12 +141,6 @@ getSchemaCache = readIORef . stateSchemaCache putSchemaCache :: AppState -> Maybe SchemaCache -> IO () putSchemaCache appState = atomicWriteIORef (stateSchemaCache appState) -getJsonDbS :: AppState -> IO ByteString -getJsonDbS = readIORef . stateJsonDbS - -putJsonDbS :: AppState -> ByteString -> IO () -putJsonDbS appState = atomicWriteIORef (stateJsonDbS appState) - getWorkerSem :: AppState -> MVar () getWorkerSem = stateWorkerSem diff --git a/src/PostgREST/Query.hs b/src/PostgREST/Query.hs index 4eec07997..b48ca98f4 100644 --- a/src/PostgREST/Query.hs +++ b/src/PostgREST/Query.hs @@ -34,8 +34,7 @@ import qualified PostgREST.SchemaCache.Proc as Proc import Data.Scientific (FPFormat (..), formatScientific, isInteger) -import PostgREST.ApiRequest (ApiRequest (..), - Target (..)) +import PostgREST.ApiRequest (ApiRequest (..)) import PostgREST.ApiRequest.Preferences (PreferCount (..), PreferParameters (..), PreferTransaction (..), @@ -235,10 +234,10 @@ optionalRollback AppConfig{..} ApiRequest{..} = do -- | Runs local (transaction scoped) GUCs for every request. setPgLocals :: AppConfig -> KM.KeyMap JSON.Value -> Text -> - ApiRequest -> ByteString -> PgVersion -> DbHandler () -setPgLocals conf claims role req jsonDbS actualPgVersion = lift $ + ApiRequest -> PgVersion -> DbHandler () +setPgLocals conf claims role req actualPgVersion = lift $ SQL.statement mempty $ SQL.dynamicallyParameterized - ("select " <> intercalateSnippet ", " (searchPathSql : roleSql ++ claimsSql ++ [methodSql, pathSql] ++ headersSql ++ cookiesSql ++ appSettingsSql ++ specSql)) + ("select " <> intercalateSnippet ", " (searchPathSql : roleSql ++ claimsSql ++ [methodSql, pathSql] ++ headersSql ++ cookiesSql ++ appSettingsSql)) HD.noResult (configDbPreparedStatements conf) where methodSql = setConfigLocal mempty ("request.method", iMethod req) @@ -257,9 +256,6 @@ setPgLocals conf claims role req jsonDbS actualPgVersion = lift $ searchPathSql = let schemas = pgFmtIdentList (iSchema req : configDbExtraSearchPath conf) in setConfigLocal mempty ("search_path", schemas) - specSql = case iTarget req of - TargetProc{tpIsRootSpec=True} -> [setConfigLocal mempty ("request.spec", jsonDbS)] - _ -> mempty usesLegacyGucs = configDbUseLegacyGucs conf && actualPgVersion < pgVersion140 unquoted :: JSON.Value -> Text diff --git a/src/PostgREST/Workers.hs b/src/PostgREST/Workers.hs index a8b760115..11fcf464c 100644 --- a/src/PostgREST/Workers.hs +++ b/src/PostgREST/Workers.hs @@ -9,9 +9,7 @@ module PostgREST.Workers , runAdmin ) where -import qualified Data.Aeson as JSON import qualified Data.ByteString as BS -import qualified Data.ByteString.Lazy as LBS import qualified Data.Text as T import qualified Hasql.Notifications as SQL import qualified Hasql.Session as SQL @@ -179,8 +177,6 @@ loadSchemaCache appState = do Right sCache -> do AppState.putSchemaCache appState (Just sCache) - when (isJust configDbRootSpec) . - AppState.putJsonDbS appState . LBS.toStrict $ JSON.encode sCache AppState.logWithZTime appState "Schema cache loaded" return SCLoaded diff --git a/test/spec/Feature/OpenApi/RootSpec.hs b/test/spec/Feature/OpenApi/RootSpec.hs index b20c257d1..c450d464a 100644 --- a/test/spec/Feature/OpenApi/RootSpec.hs +++ b/test/spec/Feature/OpenApi/RootSpec.hs @@ -9,8 +9,6 @@ import Test.Hspec.Wai.JSON import Protolude hiding (get) -import SpecHelper - spec :: SpecWith ((), Application) spec = describe "root spec function" $ do @@ -22,9 +20,3 @@ spec = "info": {"title": "PostgREST API", "description": "This is a dynamic API generated by PostgREST"} }|] { matchHeaders = ["Content-Type" <:> "application/openapi+json; charset=utf-8"] } - - it "accepts application/json" $ - request methodGet "/" - [("Accept", "application/json")] "" `shouldRespondWith` - 200 - { matchHeaders = [matchContentTypeJson] } diff --git a/test/spec/Main.hs b/test/spec/Main.hs index 9da56a3c0..65ca199d3 100644 --- a/test/spec/Main.hs +++ b/test/spec/Main.hs @@ -1,6 +1,5 @@ module Main where -import qualified Data.Aeson as JSON import qualified Hasql.Pool as P import qualified Hasql.Transaction.Sessions as HT @@ -14,7 +13,6 @@ import PostgREST.Config (AppConfig (..)) import PostgREST.Config.Database (queryPgVersion) import PostgREST.SchemaCache (querySchemaCache) import Protolude hiding (toList, toS) -import Protolude.Conv (toS) import SpecHelper import qualified PostgREST.AppState as AppState @@ -82,8 +80,6 @@ main = do appState <- AppState.initWithPool pool config AppState.putPgVersion appState actualPgVersion AppState.putSchemaCache appState (Just baseSchemaCache) - when (isJust $ configDbRootSpec config) $ - AppState.putJsonDbS appState $ toS $ JSON.encode baseSchemaCache return ((), postgrest config appState $ pure ()) -- For tests that run with a different SchemaCache(depends on configSchemas) @@ -95,8 +91,6 @@ main = do appState <- AppState.initWithPool pool config AppState.putPgVersion appState actualPgVersion AppState.putSchemaCache appState (Just customSchemaCache) - when (isJust $ configDbRootSpec config) $ - AppState.putJsonDbS appState $ toS $ JSON.encode baseSchemaCache return ((), postgrest config appState $ pure ()) let withApp = app testCfg diff --git a/test/spec/fixtures/schema.sql b/test/spec/fixtures/schema.sql index c8f40e7ba..37ec19f0e 100644 --- a/test/spec/fixtures/schema.sql +++ b/test/spec/fixtures/schema.sql @@ -1907,20 +1907,8 @@ openapi json = $$ } } $$; -accept text; begin -accept = case when current_setting('server_version_num')::int >= 140000 - then current_setting('request.headers', true)::json->>'accept' - else current_setting('request.header.accept', true) - end; -case accept - when 'application/openapi+json' then - return openapi; - when 'application/json' then - return (current_setting('request.spec', true)::json)->'dbRelationships'->0->0; - else - return openapi; - end case; + return openapi; end $_$ language plpgsql;