Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
519615d5fb | ||
|
|
de5a8954b2 | ||
|
|
64b5a59410 | ||
|
|
417a96d137 | ||
|
|
53593824a8 | ||
|
|
e642086d27 | ||
|
|
e451700d5d | ||
|
|
13868983af |
@@ -5,6 +5,15 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Unreleased
|
||||
|
||||
## [12.2.3] - 2024-08-01
|
||||
|
||||
### Fixed
|
||||
|
||||
- #3091, Broken link in OpenAPI description `externalDocs` - @salim-b
|
||||
- #3659, Embed One-to-One relationship with different column order properly - @wolfgangwalther
|
||||
- #3504, Remove `format` from `rowFilter` parameters in OpenAPI - @dantheman2865
|
||||
- #3660, Fix regression that loaded the schema cache before the in-database configuration - @steve-chavez, @laurenceisla
|
||||
|
||||
## [12.2.2] - 2024-07-10
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||

|
||||
|
||||
[](https://www.patreon.com/postgrest)
|
||||
[](https://gitter.im/begriffs/postgrest)
|
||||
[](http://postgrest.org)
|
||||
[](https://hub.docker.com/r/postgrest/postgrest/)
|
||||
[](https://github.com/PostgREST/postgrest/actions?query=branch%3Amain)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# PostgREST
|
||||
|
||||
[](https://gitter.im/begriffs/postgrest)
|
||||
[](https://www.patreon.com/postgrest)
|
||||
[](http://postgrest.org)
|
||||
[](https://github.com/PostgREST/postgrest/actions?query=branch%3Amain)
|
||||
|
||||
+1
-4
@@ -16,9 +16,6 @@ PostgREST Documentation
|
||||
.. image:: https://img.shields.io/docker/pulls/postgrest/postgrest.svg
|
||||
:target: https://hub.docker.com/r/postgrest/postgrest/
|
||||
|
||||
.. image:: https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg
|
||||
:target: https://gitter.im/begriffs/postgrest
|
||||
|
||||
.. image:: https://img.shields.io/badge/Donate-Patreon-orange.svg?colorB=F96854
|
||||
:target: https://www.patreon.com/postgrest
|
||||
|
||||
@@ -110,7 +107,7 @@ PostgREST has a focused scope. It works well with other tools like Nginx. This f
|
||||
Getting Support
|
||||
----------------
|
||||
|
||||
The project has a friendly and growing community. For discussions, use the Github `discussions page <https://github.com/PostgREST/postgrest/discussions>`_ or join our `chat room <https://gitter.im/begriffs/postgrest>`_. You can also report or search for bugs/features on the Github `issues <https://github.com/PostgREST/postgrest/issues>`_ page.
|
||||
The project has a friendly and growing community. For discussions, use the Github `discussions page <https://github.com/PostgREST/postgrest/discussions>`_. You can also report or search for bugs/features on the Github `issues <https://github.com/PostgREST/postgrest/issues>`_ page.
|
||||
|
||||
Release Notes
|
||||
-------------
|
||||
|
||||
@@ -17,12 +17,7 @@ To make an API we'll simply be building a database. All the endpoints and permis
|
||||
|
||||
By the end of this tutorial you'll have a working database, PostgREST server, and a simple single-user todo list API.
|
||||
|
||||
Step 1. Relax, we'll help
|
||||
-------------------------
|
||||
|
||||
As you begin the tutorial, pop open the project `chat room <https://gitter.im/begriffs/postgrest>`_ in another tab. There are a nice group of people active in the project and we'll help you out if you get stuck.
|
||||
|
||||
Step 2. Install PostgreSQL
|
||||
Step 1. Install PostgreSQL
|
||||
--------------------------
|
||||
|
||||
If you're already familiar with using PostgreSQL and have it installed on your system you can use the existing installation (see :ref:`pg-dependency` for minimum requirements). For this tutorial we'll describe how to use the database in Docker because database configuration is otherwise too complicated for a simple tutorial.
|
||||
@@ -48,7 +43,7 @@ This will run the Docker instance as a daemon and expose port 5432 to the host s
|
||||
In this case, you will need to change the **first** of the two 5432 to something else, for example to :code:`5433:5432`. Remember to also adjust the port in your config file in Step 5!
|
||||
|
||||
|
||||
Step 3. Install PostgREST
|
||||
Step 2. Install PostgREST
|
||||
-------------------------
|
||||
|
||||
Using a Package Manager
|
||||
@@ -122,7 +117,7 @@ If everything is working correctly it will print out its version and the availab
|
||||
</details>
|
||||
</p>
|
||||
|
||||
Step 4. Create Database for API
|
||||
Step 3. Create Database for API
|
||||
-------------------------------
|
||||
|
||||
Connect to the SQL console (psql) inside the container. To do so, run this from your command line:
|
||||
@@ -185,7 +180,7 @@ Now quit out of psql; it's time to start the API!
|
||||
|
||||
\q
|
||||
|
||||
Step 5. Run PostgREST
|
||||
Step 4. Run PostgREST
|
||||
---------------------
|
||||
|
||||
PostgREST can use a configuration file to tell it how to connect to the database. Create a file :code:`tutorial.conf` with this inside:
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
name: postgrest
|
||||
version: 12.2.2
|
||||
version: 12.2.3
|
||||
synopsis: REST API for any Postgres database
|
||||
description: Reads the schema of a PostgreSQL database and creates RESTful routes
|
||||
for tables, views, and functions, supporting all HTTP methods that security
|
||||
|
||||
+11
-11
@@ -161,7 +161,7 @@ initWithPool (sock, adminSock) pool conf loggerState metricsState observer = do
|
||||
deb <-
|
||||
let decisecond = 100000 in
|
||||
mkDebounce defaultDebounceSettings
|
||||
{ debounceAction = internalSchemaCacheLoad appState
|
||||
{ debounceAction = retryingSchemaCacheLoad appState
|
||||
, debounceFreq = decisecond
|
||||
, debounceEdge = leadingEdge -- runs the worker at the start and the end
|
||||
}
|
||||
@@ -354,13 +354,6 @@ putSCacheStatus = atomicWriteIORef . stateSCacheStatus
|
||||
getObserver :: AppState -> ObservationHandler
|
||||
getObserver = stateObserver
|
||||
|
||||
internalSchemaCacheLoad :: AppState -> IO ()
|
||||
internalSchemaCacheLoad appState = do
|
||||
AppConfig{..} <- getConfig appState
|
||||
void $ retryingSchemaCacheLoad appState
|
||||
-- We cannot retry reading the in-db config after it fails immediately, because it could have user errors. We just report the error and continue.
|
||||
when configDbConfig $ readInDbConfig False appState
|
||||
|
||||
-- | Try to load the schema cache and retry if it fails.
|
||||
--
|
||||
-- This is done by repeatedly: 1) flushing the pool, 2) querying the version and validating that the postgres version is supported by us, and 3) loading the schema cache.
|
||||
@@ -368,16 +361,17 @@ internalSchemaCacheLoad appState = do
|
||||
--
|
||||
-- + Because connections cache the pg catalog(see #2620)
|
||||
-- + For rapid recovery. Otherwise, the pool idle or lifetime timeout would have to be reached for new healthy connections to be acquired.
|
||||
retryingSchemaCacheLoad :: AppState -> IO (Maybe PgVersion, Maybe SchemaCache)
|
||||
retryingSchemaCacheLoad :: AppState -> IO ()
|
||||
retryingSchemaCacheLoad appState@AppState{stateObserver=observer, stateMainThreadId=mainThreadId} =
|
||||
retrying retryPolicy shouldRetry (\RetryStatus{rsIterNumber, rsPreviousDelay} -> do
|
||||
void $ retrying retryPolicy shouldRetry (\RetryStatus{rsIterNumber, rsPreviousDelay} -> do
|
||||
when (rsIterNumber > 0) $ do
|
||||
let delay = fromMaybe 0 rsPreviousDelay `div` oneSecondInUs
|
||||
observer $ ConnectionRetryObs delay
|
||||
putNextListenerDelay appState delay
|
||||
|
||||
flushPool appState
|
||||
(,) <$> qPgVersion <*> qSchemaCache
|
||||
|
||||
(,) <$> qPgVersion <*> (qInDbConfig *> qSchemaCache)
|
||||
)
|
||||
where
|
||||
qPgVersion :: IO (Maybe PgVersion)
|
||||
@@ -399,6 +393,11 @@ retryingSchemaCacheLoad appState@AppState{stateObserver=observer, stateMainThrea
|
||||
putPgVersion appState actualPgVersion
|
||||
return $ Just actualPgVersion
|
||||
|
||||
qInDbConfig :: IO ()
|
||||
qInDbConfig = do
|
||||
AppConfig{..} <- getConfig appState
|
||||
when configDbConfig $ readInDbConfig False appState
|
||||
|
||||
qSchemaCache :: IO (Maybe SchemaCache)
|
||||
qSchemaCache = do
|
||||
conf@AppConfig{..} <- getConfig appState
|
||||
@@ -437,6 +436,7 @@ retryingSchemaCacheLoad appState@AppState{stateObserver=observer, stateMainThrea
|
||||
oneSecondInUs = 1000000 -- one second in microseconds
|
||||
|
||||
-- | Reads the in-db config and reads the config file again
|
||||
-- | We don't retry reading the in-db config after it fails immediately, because it could have user errors. We just report the error and continue.
|
||||
readInDbConfig :: Bool -> AppState -> IO ()
|
||||
readInDbConfig startingUp appState@AppState{stateObserver=observer} = do
|
||||
AppConfig{..} <- getConfig appState
|
||||
|
||||
@@ -296,8 +296,7 @@ makeRowFilter tn c =
|
||||
& required ?~ False
|
||||
& schema .~ ParamOther ((mempty :: ParamOtherSchema)
|
||||
& in_ .~ ParamQuery
|
||||
& type_ ?~ SwaggerString
|
||||
& format ?~ colType c))
|
||||
& type_ ?~ SwaggerString))
|
||||
|
||||
makeRowFilters :: Text -> [Column] -> [(Text, Param)]
|
||||
makeRowFilters tn = fmap (makeRowFilter tn)
|
||||
@@ -402,7 +401,7 @@ postgrestSpec (prettyVersion, docsVersion) rels pds ti (s, h, p, b) sd allowSecu
|
||||
& description ?~ fromMaybe "This is a dynamic API generated by PostgREST" dDesc)
|
||||
& externalDocs ?~ ((mempty :: ExternalDocs)
|
||||
& description ?~ "PostgREST Documentation"
|
||||
& url .~ URL ("https://postgrest.org/en/" <> docsVersion <> "/api.html"))
|
||||
& url .~ URL ("https://postgrest.org/en/" <> docsVersion <> "/references/api.html"))
|
||||
& host .~ h'
|
||||
& definitions .~ fromList (makeTableDef rels <$> ti)
|
||||
& parameters .~ fromList (makeParamDefs ti)
|
||||
|
||||
@@ -872,7 +872,7 @@ allM2OandO2ORels pgVer =
|
||||
JOIN LATERAL (
|
||||
SELECT
|
||||
array_agg(row(cols.attname, refs.attname) order by ord) AS cols_and_fcols,
|
||||
jsonb_agg(cols.attname order by ord) AS cols
|
||||
jsonb_agg(cols.attname order by cols.attnum) AS cols
|
||||
FROM unnest(traint.conkey, traint.confkey) WITH ORDINALITY AS _(col, ref, ord)
|
||||
JOIN pg_attribute cols ON cols.attrelid = traint.conrelid AND cols.attnum = col
|
||||
JOIN pg_attribute refs ON refs.attrelid = traint.confrelid AND refs.attnum = ref
|
||||
|
||||
@@ -218,6 +218,40 @@
|
||||
pdSchema: public
|
||||
pdVolatility: Volatile
|
||||
|
||||
- - qiName: reset_db_schemas_config
|
||||
qiSchema: public
|
||||
- - pdDescription: null
|
||||
pdFuncSettings: []
|
||||
pdHasVariadic: false
|
||||
pdName: reset_db_schemas_config
|
||||
pdParams: []
|
||||
pdReturnType:
|
||||
contents:
|
||||
contents:
|
||||
qiName: void
|
||||
qiSchema: pg_catalog
|
||||
tag: Scalar
|
||||
tag: Single
|
||||
pdSchema: public
|
||||
pdVolatility: Volatile
|
||||
|
||||
- - qiName: change_db_schemas_config
|
||||
qiSchema: public
|
||||
- - pdDescription: null
|
||||
pdFuncSettings: []
|
||||
pdHasVariadic: false
|
||||
pdName: change_db_schemas_config
|
||||
pdParams: []
|
||||
pdReturnType:
|
||||
contents:
|
||||
contents:
|
||||
qiName: void
|
||||
qiSchema: pg_catalog
|
||||
tag: Scalar
|
||||
tag: Single
|
||||
pdSchema: public
|
||||
pdVolatility: Volatile
|
||||
|
||||
- - qiName: change_db_schema_and_full_reload
|
||||
qiSchema: public
|
||||
- - pdDescription: null
|
||||
|
||||
@@ -33,6 +33,9 @@ GRANT
|
||||
CREATE SCHEMA v1;
|
||||
GRANT USAGE ON SCHEMA v1 TO postgrest_test_anonymous;
|
||||
|
||||
CREATE SCHEMA test;
|
||||
GRANT USAGE ON SCHEMA test TO postgrest_test_anonymous;
|
||||
|
||||
CREATE TABLE authors_only ();
|
||||
GRANT SELECT ON authors_only TO postgrest_test_author;
|
||||
|
||||
@@ -226,3 +229,17 @@ $$ language sql;
|
||||
create function get_statement_timeout(items) returns text as $$
|
||||
select current_setting('statement_timeout', true) as statement_timeout
|
||||
$$ language sql;
|
||||
|
||||
create function change_db_schemas_config() returns void as $_$
|
||||
begin
|
||||
alter role postgrest_test_authenticator set pgrst.db_schemas = 'test';
|
||||
end $_$ volatile security definer language plpgsql;
|
||||
|
||||
create function reset_db_schemas_config() returns void as $_$
|
||||
begin
|
||||
alter role postgrest_test_authenticator reset pgrst.db_schemas;
|
||||
end $_$ volatile security definer language plpgsql ;
|
||||
|
||||
create function test.get_current_schema() returns text as $$
|
||||
select current_schema()::text;
|
||||
$$ language sql;
|
||||
|
||||
@@ -1579,3 +1579,20 @@ def test_admin_metrics(defaultenv):
|
||||
assert "pgrst_db_pool_waiting" in response.text
|
||||
assert "pgrst_db_pool_available" in response.text
|
||||
assert "pgrst_db_pool_timeouts_total" in response.text
|
||||
|
||||
|
||||
def test_schema_cache_startup_load_with_in_db_config(defaultenv, metapostgrest):
|
||||
"verify that the Schema Cache loads correctly at startup, using the in-db `pgrst.db_schemas` config"
|
||||
|
||||
response = metapostgrest.session.post("/rpc/change_db_schemas_config")
|
||||
assert response.text == ""
|
||||
assert response.status_code == 204
|
||||
|
||||
with run(env=defaultenv) as postgrest:
|
||||
response = postgrest.session.get("/rpc/get_current_schema")
|
||||
assert response.text == '"test"'
|
||||
assert response.status_code == 200
|
||||
|
||||
response = metapostgrest.session.post("/rpc/reset_db_schemas_config")
|
||||
assert response.text == ""
|
||||
assert response.status_code == 204
|
||||
|
||||
@@ -45,7 +45,7 @@ spec actualPgVersion = describe "OpenAPI" $ do
|
||||
|
||||
let docsUrl = r ^? key "externalDocs" . key "url"
|
||||
|
||||
liftIO $ docsUrl `shouldBe` Just (String ("https://postgrest.org/en/" <> docsVersion <> "/api.html"))
|
||||
liftIO $ docsUrl `shouldBe` Just (String ("https://postgrest.org/en/" <> docsVersion <> "/references/api.html"))
|
||||
|
||||
describe "schema" $ do
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -2872,7 +2872,7 @@ CREATE TABLE test.students_info(
|
||||
, code text
|
||||
, address text
|
||||
, primary key(id, code)
|
||||
, foreign key (id, code) references test.students(id, code) on delete cascade
|
||||
, foreign key (code, id) references test.students(code, id) on delete cascade
|
||||
);
|
||||
|
||||
CREATE TABLE test.country(
|
||||
|
||||
Reference in New Issue
Block a user