Compare commits
@@ -1,5 +1,5 @@
|
||||
freebsd_instance:
|
||||
image_family: freebsd-14-0
|
||||
image_family: freebsd-14-3
|
||||
|
||||
build_task:
|
||||
# Don't change this name without adjusting .github/workflows/build.yaml
|
||||
@@ -35,7 +35,7 @@ build_task:
|
||||
- find main src -type f -iname '*.hs' -exec md5sum "{}" +
|
||||
|
||||
build_script: |
|
||||
stack build -j 1 --local-bin-path . --copy-bins --stack-yaml stack-21.7.yaml
|
||||
stack build -j 1 --local-bin-path . --copy-bins
|
||||
strip postgrest
|
||||
|
||||
bin_artifacts:
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
@@ -1,55 +0,0 @@
|
||||
# Contributing to PostgREST
|
||||
|
||||
**First:** if you're unsure or afraid of _anything_, just ask or
|
||||
submit the issue or pull request anyways. You won't be yelled at
|
||||
for giving your best effort. The worst that can happen is that
|
||||
you'll be politely asked to change something. We appreciate any
|
||||
sort of contributions, and don't want a wall of rules to get in the
|
||||
way of that.
|
||||
|
||||
However, for those individuals who want a bit more guidance on the
|
||||
best way to contribute to the project, read on. This document will
|
||||
cover what we're looking for. By addressing all the points we're
|
||||
looking for, it raises the chances we can quickly merge or address
|
||||
your contributions.
|
||||
|
||||
## Issues
|
||||
|
||||
For questions on how to use PostgREST, please use
|
||||
[GitHub discussions](https://github.com/PostgREST/postgrest/discussions).
|
||||
|
||||
### Reporting an Issue
|
||||
|
||||
* Make sure you test against the latest [stable release](https://github.com/PostgREST/postgrest/releases/latest)
|
||||
and also against the latest [nightly release](https://github.com/PostgREST/postgrest/releases/tag/nightly).
|
||||
It is possible we already fixed the bug you're experiencing.
|
||||
|
||||
* Provide steps to reproduce the issue, including your OS version and
|
||||
the specific database schema that you are using.
|
||||
|
||||
* Please include SQL logs for issues involving runtime problems. To obtain logs first
|
||||
[enable logging all statements](http://www.microhowto.info/howto/log_all_queries_to_a_postgresql_server.html),
|
||||
then [find your logs](http://blog.endpoint.com/2014/11/dear-postgresql-where-are-my-logs.html).
|
||||
|
||||
* If your database schema has changed while the PostgREST server is running,
|
||||
[send the server a `SIGUSR1` signal](http://postgrest.org/en/latest/admin.html#schema-reloading) or restart it to ensure the schema cache
|
||||
is not stale. This sometimes fixes apparent bugs.
|
||||
|
||||
## Code
|
||||
|
||||
We have a fully nix-based development environment with many tools for a smooth development workflow available.
|
||||
Check the [development docs](https://github.com/PostgREST/postgrest/blob/main/nix/README.md) on how to set it up and use it.
|
||||
|
||||
### Haskell Conventions
|
||||
|
||||
* All contributions must pass the tests before being merged. When
|
||||
you create a pull request your code will automatically be tested.
|
||||
|
||||
* All code must also pass [hlint](http://community.haskell.org/~ndm/hlint/) and [stylish-haskell](https://github.com/jaspervdj/stylish-haskell)
|
||||
with no warnings. This helps enforce a uniform style for all committers. Continuous integration will check this as well on every
|
||||
pull request. There are useful tools in the nix-shell that help with checking this locally. You can run `postgrest-check` to do this manually but
|
||||
we recommend adding it to `.git/hooks/pre-commit` as `nix-shell --run postgrest-check` to automatically check this before doing a commit.
|
||||
|
||||
### Running Tests
|
||||
|
||||
For instructions on running tests, see the [development docs](https://github.com/PostgREST/postgrest/blob/main/nix/README.md#testing).
|
||||
@@ -1,17 +0,0 @@
|
||||
<!--
|
||||
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/stable/admin.html#schema-reloading)
|
||||
to ensure the schema cache is not stale. This sometimes fixes apparent bugs.
|
||||
-->
|
||||
### Environment
|
||||
|
||||
* PostgreSQL version: (if using docker, specify the image)
|
||||
* PostgREST version: (if using docker, specify the image)
|
||||
* Operating system:
|
||||
|
||||
### Description of issue
|
||||
|
||||
(Expected behavior vs actual behavior)
|
||||
|
||||
(Steps to reproduce: Include a minimal SQL definition plus how you make the request to PostgREST and the response body)
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a bug report to help us improve
|
||||
type: Bug
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
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/stable/admin.html#schema-reloading) to ensure the schema cache is not stale. This sometimes fixes apparent bugs.
|
||||
-->
|
||||
### Environment
|
||||
|
||||
* PostgreSQL version: (if using docker, specify the image)
|
||||
* PostgREST version: (if using docker, specify the image)
|
||||
* Operating system:
|
||||
|
||||
### Description of issue
|
||||
|
||||
Describe the behavior you expected vs the actual behavior. Include:
|
||||
|
||||
- A minimal SQL definition.
|
||||
- How you make the request to PostgREST (curl command preferred).
|
||||
- The PostgREST response.
|
||||
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an enhancement for this project
|
||||
type: Feature
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Problem
|
||||
|
||||
A clear and concise description of what the problem is.
|
||||
|
||||
## Solution
|
||||
|
||||
A clear and concise description of what you want to happen.
|
||||
@@ -4,17 +4,18 @@ When submitting a new feature or fix:
|
||||
- Add a new entry to the CHANGELOG - https://github.com/PostgREST/postgrest/blob/main/CHANGELOG.md#unreleased
|
||||
- If relevant, update the docs
|
||||
- Use a prefix for the PR title or commits, e.g. "fix: description of the fix".
|
||||
+ `fix`, bug fixes
|
||||
+ `feat`, new features added
|
||||
+ `perf`, performance improvements
|
||||
+ `docs`, updating the documentation
|
||||
+ `nix`, related to the Nix development environment
|
||||
+ `ci`, related to the Continuous Integration modules
|
||||
+ `test`, related to the testing modules
|
||||
+ `refactor`, refactoring code
|
||||
+ `deprecate`, deprecating a feature
|
||||
+ `changelog`, updating the CHANGELOG
|
||||
+ `chore`, maintenance (build process, updating sponsors, etc.)
|
||||
+ `add`, Add a new feature
|
||||
+ `amend`, To amend an unrealease commit
|
||||
+ `change`, Breaking changes
|
||||
+ `chore`, Maintenance, update sponsors, changelog, readme etc
|
||||
+ `ci`, CI configuration files and scripts
|
||||
+ `docs`, Documentation
|
||||
+ `fix`, Bug fix
|
||||
+ `nix`, Related to Nix
|
||||
+ `perf`, Performance improvements
|
||||
+ `refactor`, Refactoring code
|
||||
+ `remove`, Remove a feature or fix
|
||||
+ `test`, Adding tests
|
||||
+ Other prefixes may be used if necessary
|
||||
- If there's a breaking change, add `BREAKING CHANGE` and an explanation to your commit message
|
||||
-->
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# TODO: Remove this once a new actionlint release has been cut
|
||||
# and made its way to us through nixpkgs.
|
||||
self-hosted-runner:
|
||||
labels:
|
||||
- macos-15-intel
|
||||
- ubuntu-24.04-arm
|
||||
@@ -112,7 +112,7 @@ runs:
|
||||
echo "artifacts=${artifacts}" >> "$GITHUB_OUTPUT"
|
||||
- name: Save artifact to GitHub Actions
|
||||
if: steps.find-task.outputs.task_found
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: ${{ inputs.upload }}
|
||||
path: ${{ steps.download.outputs.artifacts }}
|
||||
|
||||
@@ -19,14 +19,14 @@ inputs:
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||
- uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
if: ${{ startsWith(github.ref, 'refs/heads/') || (inputs.save-prs && startsWith(github.ref, 'refs/pull/')) }}
|
||||
with:
|
||||
path: ${{ inputs.path }}
|
||||
key: ${{ runner.os }}-${{ inputs.prefix }}-${{ inputs.suffix }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ inputs.prefix }}-
|
||||
- uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||
- uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
if: ${{ !startsWith(github.ref, 'refs/heads/') && !(inputs.save-prs && startsWith(github.ref, 'refs/pull/')) }}
|
||||
with:
|
||||
path: ${{ inputs.path }}
|
||||
|
||||
@@ -11,15 +11,16 @@ inputs:
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: nixbuild/nix-quick-install-action@60e9c39264d4714139af3cdf15f691b19eec3530 # v28
|
||||
- uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
|
||||
with:
|
||||
nix_conf: |-
|
||||
always-allow-substitutes = true
|
||||
max-jobs = auto
|
||||
- uses: cachix/cachix-action@ad2ddac53f961de1989924296a1f236fcfbaa4fc # v15
|
||||
- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
|
||||
with:
|
||||
name: postgrest
|
||||
authToken: ${{ inputs.authToken }}
|
||||
skipPush: ${{ inputs.authToken == '' }}
|
||||
- if: ${{ inputs.tools }}
|
||||
run: nix-env -f default.nix -iA ${{ inputs.tools }}
|
||||
shell: bash
|
||||
|
||||
@@ -3,23 +3,67 @@
|
||||
"extends": [
|
||||
"config:best-practices"
|
||||
],
|
||||
"baseBranches": [
|
||||
"baseBranchPatterns": [
|
||||
"main",
|
||||
"/^v[0-9]+/"
|
||||
],
|
||||
"rebaseWhen": "conflicted",
|
||||
"pip_requirements": {
|
||||
"enabled": false
|
||||
},
|
||||
"packageRules": [
|
||||
{
|
||||
"matchBaseBranches": [ "/^v[0-9]+/" ],
|
||||
"matchBaseBranches": [
|
||||
"/^v[0-9]+/"
|
||||
],
|
||||
"matchManagers": [
|
||||
"haskell-cabal"
|
||||
],
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"matchBaseBranches": [
|
||||
"/^v[0-9]+/"
|
||||
],
|
||||
"groupName": "all dependencies"
|
||||
},
|
||||
{
|
||||
"matchPackageNames": ["docutils"],
|
||||
"allowedVersions": "<0.21.0"
|
||||
"matchManagers": [
|
||||
"haskell-cabal"
|
||||
],
|
||||
"matchPackageNames": [
|
||||
"base",
|
||||
"bytestring",
|
||||
"containers",
|
||||
"directory",
|
||||
"mtl",
|
||||
"parsec",
|
||||
"process",
|
||||
"text"
|
||||
],
|
||||
"groupName": "GHC dependencies"
|
||||
},
|
||||
{
|
||||
"matchPackageNames": ["macos"],
|
||||
"allowedVersions": "<13"
|
||||
"matchManagers": [
|
||||
"haskell-cabal"
|
||||
],
|
||||
"matchPackageNames": [
|
||||
"hasql",
|
||||
"hasql-dynamic-statements",
|
||||
"hasql-notifications",
|
||||
"hasql-transaction",
|
||||
"hasql-pool"
|
||||
],
|
||||
"groupName": "hasql"
|
||||
},
|
||||
{
|
||||
"matchManagers": [
|
||||
"haskell-cabal"
|
||||
],
|
||||
"matchPackageNames": [
|
||||
"fuzzyset"
|
||||
],
|
||||
"allowedVersions": "<0.3"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
# This script builds PostgREST in a remote ARM server
|
||||
|
||||
[ -z "$1" ] && { echo "Missing 1st argument: PostgREST github commit SHA"; exit 1; }
|
||||
[ -z "$2" ] && { echo "Missing 2nd argument: Build environment directory name"; exit 1; }
|
||||
[ -z "$3" ] && { echo "Missing 3rd argument: GHC version"; exit 1; }
|
||||
|
||||
PGRST_GITHUB_COMMIT="$1"
|
||||
SCRIPT_DIR="$2"
|
||||
|
||||
DOCKER_BUILD_DIR="$SCRIPT_DIR/docker-env"
|
||||
# latest is a shortcut documented on https://www.haskell.org/ghcup/guide/#tags-and-shortcuts
|
||||
CABAL_VERSION="latest"
|
||||
GHC_VERSION="$3"
|
||||
|
||||
install_packages() {
|
||||
sudo apt-get update -y
|
||||
sudo apt-get upgrade -y
|
||||
sudo apt-get install -y git build-essential curl libffi-dev libffi7 libgmp-dev libgmp10 libncurses-dev libncurses5 libtinfo5 llvm libnuma-dev zlib1g-dev libpq-dev jq gcc
|
||||
sudo apt-get clean
|
||||
}
|
||||
|
||||
install_ghcup() {
|
||||
export BOOTSTRAP_HASKELL_NONINTERACTIVE=1
|
||||
export BOOTSTRAP_HASKELL_MINIMAL=1
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
|
||||
source ~/.ghcup/env
|
||||
}
|
||||
|
||||
install_cabal() {
|
||||
ghcup upgrade
|
||||
ghcup install cabal $CABAL_VERSION
|
||||
ghcup set cabal $CABAL_VERSION
|
||||
}
|
||||
|
||||
install_ghc() {
|
||||
ghcup upgrade
|
||||
ghcup install ghc $GHC_VERSION
|
||||
ghcup set ghc $GHC_VERSION
|
||||
}
|
||||
|
||||
install_packages
|
||||
|
||||
# Add ghcup to the PATH for this session
|
||||
[ -f ~/.ghcup/env ] && source ~/.ghcup/env
|
||||
|
||||
ghcup --version || install_ghcup
|
||||
ghcup set cabal $CABAL_VERSION || install_cabal
|
||||
ghcup set ghc $GHC_VERSION || install_ghc
|
||||
|
||||
cd ~/$SCRIPT_DIR
|
||||
|
||||
# Clone the repository and build the project
|
||||
git clone https://github.com/PostgREST/postgrest.git
|
||||
cd postgrest
|
||||
git checkout $PGRST_GITHUB_COMMIT
|
||||
cabal v2-update && cabal v2-build
|
||||
|
||||
# Strip unused symbols from executable
|
||||
PGRST_BIN=$(cabal exec which postgrest | tail -1)
|
||||
strip $PGRST_BIN
|
||||
|
||||
# Copy the built binary to the Dockerfile directory
|
||||
cp $PGRST_BIN ~/$DOCKER_BUILD_DIR
|
||||
|
||||
# Move and compress the built binary
|
||||
mkdir -p ~/$SCRIPT_DIR/result
|
||||
mv $PGRST_BIN ~/$SCRIPT_DIR/result
|
||||
cd ~/$SCRIPT_DIR
|
||||
tar -cJf result.tar.xz result
|
||||
@@ -1,50 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
# This script publishes the Docker ARM images to Docker Hub.
|
||||
|
||||
[ -z "$1" ] && { echo "Missing 1st argument: PostgREST github commit SHA"; exit 1; }
|
||||
[ -z "$2" ] && { echo "Missing 2nd argument: Docker repo"; exit 1; }
|
||||
[ -z "$3" ] && { echo "Missing 3rd argument: Docker username"; exit 1; }
|
||||
[ -z "$4" ] && { echo "Missing 4th argument: Docker password"; exit 1; }
|
||||
[ -z "$5" ] && { echo "Missing 5th argument: Build environment directory name"; exit 1; }
|
||||
[ -z "$6" ] && { echo "Missing 6th argument: PostgREST version"; exit 1; }
|
||||
|
||||
PGRST_GITHUB_COMMIT="$1"
|
||||
DOCKER_REPO="$2"
|
||||
DOCKER_USER="$3"
|
||||
DOCKER_PASS="$4"
|
||||
SCRIPT_DIR="$5"
|
||||
PGRST_VERSION="$6"
|
||||
|
||||
DOCKER_BUILD_DIR="$SCRIPT_DIR/docker-env"
|
||||
|
||||
clean_env()
|
||||
{
|
||||
sudo docker logout
|
||||
}
|
||||
|
||||
# Login to Docker
|
||||
sudo docker logout
|
||||
{ echo $DOCKER_PASS | sudo docker login -u $DOCKER_USER --password-stdin; } || { echo "Couldn't login to docker"; exit 1; }
|
||||
|
||||
trap clean_env sigint sigterm exit
|
||||
|
||||
# Move to the docker build environment
|
||||
cd ~/$DOCKER_BUILD_DIR
|
||||
|
||||
# Push final images to Docker hub
|
||||
# NOTE: This command publishes a separate ARM image because the builds cannot
|
||||
# be added to the manifest if they are not in the registry beforehand.
|
||||
# This image must be manually deleted from Docker Hub at the end of the process.
|
||||
sudo docker buildx build --build-arg PGRST_GITHUB_COMMIT=$PGRST_GITHUB_COMMIT \
|
||||
-t $DOCKER_REPO/postgrest:$PGRST_VERSION-arm \
|
||||
--push .
|
||||
|
||||
# Add the arm images to the manifest
|
||||
# NOTE: This assumes that there already is a `postgrest:<version>` image
|
||||
# for the amd64 architecture pushed to Docker Hub
|
||||
sudo docker buildx imagetools create --append -t $DOCKER_REPO/postgrest:$PGRST_VERSION $DOCKER_REPO/postgrest:$PGRST_VERSION-arm
|
||||
[ "$PGRST_VERSION" != "devel" ] && sudo docker buildx imagetools create --append -t $DOCKER_REPO/postgrest:latest $DOCKER_REPO/postgrest:$PGRST_VERSION-arm
|
||||
|
||||
sudo docker logout
|
||||
@@ -0,0 +1,52 @@
|
||||
name: Backport
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- closed
|
||||
- labeled
|
||||
|
||||
jobs:
|
||||
backport:
|
||||
name: Backport
|
||||
runs-on: ubuntu-24.04
|
||||
# It triggers only when PR is already merged on either:
|
||||
#
|
||||
# - The merge event itself (action != labeled) or
|
||||
# - A label event with the right label (backport ...).
|
||||
#
|
||||
# The result will be that we can add the label before or after merge,
|
||||
# but the workflow will only run once the PR had been merged.
|
||||
if: >
|
||||
github.event.pull_request.merged &&
|
||||
(
|
||||
github.event.action != 'labeled' ||
|
||||
startsWith(github.event.label.name, 'backport')
|
||||
)
|
||||
steps:
|
||||
|
||||
# This actions creates the github token using the postgrest app secrets
|
||||
- name: Create Github App Token
|
||||
id: app-token
|
||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
|
||||
with:
|
||||
app-id: ${{ vars.POSTGREST_CI_APP_ID }}
|
||||
private-key: ${{ secrets.POSTGREST_CI_PRIVATE_KEY }}
|
||||
permission-contents: write
|
||||
permission-pull-requests: write
|
||||
permission-workflows: write # required when backporting CI changes
|
||||
|
||||
# This is required for backport action to cherry-pick the PR
|
||||
- name: Fetch PR ref
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
# Backport action that creates the PR with given settings
|
||||
- name: Create backport PR
|
||||
uses: korthout/backport-action@7c3f6cd5843cac11bc59a04a1b7699af93261670 # v4.5
|
||||
with:
|
||||
github_token: ${{ steps.app-token.outputs.token }}
|
||||
pull_description: 'Backport for #${pull_number}.'
|
||||
pull_title: '${target_branch}: ${pull_title}'
|
||||
@@ -30,39 +30,39 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
static:
|
||||
name: Nix - Linux static
|
||||
runs-on: ubuntu-22.04
|
||||
name: Nix - Linux x86-64 static
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Nix Environment
|
||||
uses: ./.github/actions/setup-nix
|
||||
with:
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
|
||||
- name: Build static executable
|
||||
run: nix-build -A postgrestStatic
|
||||
run: nix-build -A postgrestStatic -A postgrestStatic.tests
|
||||
- name: Save built executable as artifact
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: postgrest-linux-static-x64
|
||||
name: postgrest-linux-static-x86-64
|
||||
path: result/bin/postgrest
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Build Docker image
|
||||
run: nix-build -A docker.image --out-link postgrest-docker.tar.gz
|
||||
- name: Save built Docker image as artifact
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: postgrest-docker-x64
|
||||
name: postgrest-docker-x86-64
|
||||
path: postgrest-docker.tar.gz
|
||||
if-no-files-found: error
|
||||
|
||||
|
||||
macos:
|
||||
name: Nix - MacOS
|
||||
runs-on: macos-12
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Nix Environment
|
||||
uses: ./.github/actions/setup-nix
|
||||
with:
|
||||
@@ -87,42 +87,50 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: Linux
|
||||
runs-on: ubuntu-22.04
|
||||
- name: Linux aarch64
|
||||
runs-on: ubuntu-24.04-arm
|
||||
cache: |
|
||||
~/.stack/pantry
|
||||
~/.stack/snapshots
|
||||
~/.stack/stack.sqlite3
|
||||
# no artifact for Linux, because we use the static build
|
||||
artifact: postgrest-ubuntu-aarch64
|
||||
deps: sudo apt-get update && sudo apt-get install libpq-dev
|
||||
|
||||
- name: MacOS
|
||||
runs-on: macos-12
|
||||
- name: MacOS aarch64
|
||||
runs-on: macos-14
|
||||
cache: |
|
||||
~/.stack/pantry
|
||||
~/.stack/snapshots
|
||||
~/.stack/stack.sqlite3
|
||||
artifact: postgrest-macos-x64
|
||||
artifact: postgrest-macos-aarch64
|
||||
deps: brew link --force libpq
|
||||
|
||||
- name: MacOS x86-64
|
||||
runs-on: macos-15-intel
|
||||
cache: |
|
||||
~/.stack/pantry
|
||||
~/.stack/snapshots
|
||||
~/.stack/stack.sqlite3
|
||||
artifact: postgrest-macos-x86-64
|
||||
deps: brew link --force libpq
|
||||
|
||||
- name: Windows
|
||||
runs-on: windows-2022
|
||||
cache: |
|
||||
~\AppData\Roaming\stack\pantry
|
||||
~\AppData\Local\Programs\stack\pantry
|
||||
~\AppData\Roaming\stack\snapshots
|
||||
~\AppData\Local\Programs\stack\snapshots
|
||||
~\AppData\Roaming\stack\stack.sqlite3
|
||||
~\AppData\Local\Programs\stack\stack.sqlite3
|
||||
C:\sr\pantry
|
||||
C:\sr\snapshots
|
||||
C:\sr\stack.sqlite3
|
||||
deps: Add-Content $env:GITHUB_PATH $env:PGBIN
|
||||
artifact: postgrest-windows-x64
|
||||
artifact: postgrest-windows-x86-64
|
||||
|
||||
name: Stack - ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: haskell-actions/setup@33585e1a16afa5875e124b0ebc89dd0c2f872c21 # v2.7.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: haskell-actions/setup@cd0d9bdd65b20557f41bea4dbe43d0b5fbbfe553 # v2.11.0
|
||||
with:
|
||||
# This must match the version in stack.yaml's resolver
|
||||
ghc-version: 9.6.5
|
||||
ghc-version: 9.6.7
|
||||
enable-stack: true
|
||||
stack-no-global: true
|
||||
stack-setup-ghc: true
|
||||
@@ -147,8 +155,7 @@ jobs:
|
||||
- name: Strip Executable
|
||||
run: strip result/postgrest*
|
||||
- name: Save built executable as artifact
|
||||
if: matrix.artifact
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: ${{ matrix.artifact }}
|
||||
path: |
|
||||
@@ -159,27 +166,27 @@ jobs:
|
||||
|
||||
freebsd:
|
||||
name: Stack - FreeBSD from CirrusCI
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: ./.github/actions/artifact-from-cirrus
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
task: Build FreeBSD (Stack)
|
||||
download: bin
|
||||
upload: postgrest-freebsd-x64
|
||||
upload: postgrest-freebsd-x86-64
|
||||
|
||||
|
||||
cabal:
|
||||
strategy:
|
||||
matrix:
|
||||
ghc: ['9.6.4', '9.8.2']
|
||||
ghc: ['9.6.7', '9.8.4']
|
||||
fail-fast: false
|
||||
name: Cabal - Linux GHC ${{ matrix.ghc }}
|
||||
runs-on: ubuntu-22.04
|
||||
name: Cabal - Linux x86-64 - GHC ${{ matrix.ghc }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: haskell-actions/setup@33585e1a16afa5875e124b0ebc89dd0c2f872c21 # v2.7.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: haskell-actions/setup@cd0d9bdd65b20557f41bea4dbe43d0b5fbbfe553 # v2.11.0
|
||||
with:
|
||||
ghc-version: ${{ matrix.ghc }}
|
||||
- name: Cache .cabal
|
||||
@@ -188,8 +195,8 @@ jobs:
|
||||
path: |
|
||||
~/.cabal/packages
|
||||
~/.cabal/store
|
||||
prefix: cabal-${{ matrix.ghc }}
|
||||
suffix: ${{ hashFiles('postgrest.cabal', 'cabal.project', 'cabal.project.freeze') }}
|
||||
prefix: cabal-${{ matrix.ghc }}-${{ hashFiles('cabal.project.freeze') }}
|
||||
suffix: ${{ hashFiles('postgrest.cabal', 'cabal.project') }}
|
||||
- name: Cache dist-newstyle
|
||||
uses: ./.github/actions/cache-on-main
|
||||
with:
|
||||
|
||||
@@ -18,9 +18,9 @@ concurrency:
|
||||
jobs:
|
||||
lint-style:
|
||||
name: Lint & Style
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Nix Environment
|
||||
uses: ./.github/actions/setup-nix
|
||||
with:
|
||||
@@ -30,3 +30,24 @@ jobs:
|
||||
run: postgrest-lint
|
||||
- name: Run style check (auto-format with `nix-shell --run postgrest-style`)
|
||||
run: postgrest-style-check
|
||||
|
||||
commit:
|
||||
if: github.event_name != 'push' # we don't run this on a push, a failure on push disrupts the release workflow
|
||||
name: Commit
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 100 # fetch history (last 100 commits) instead of default shallow clone history, this is deemed enough for a PR history
|
||||
- name: Setup Nix Environment
|
||||
uses: ./.github/actions/setup-nix
|
||||
with:
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
tools: gitTools.commitCheck.bin
|
||||
- name: Run commitlint (check locally with `nix-shell --run postgrest-commitlint`)
|
||||
run: |
|
||||
# Fetch target branch explicitly
|
||||
git fetch origin ${{ github.base_ref }}
|
||||
|
||||
# Run commitlint
|
||||
postgrest-commitlint --from origin/${{ github.base_ref }} --to HEAD
|
||||
|
||||
@@ -5,21 +5,10 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- v[0-9]+
|
||||
tags:
|
||||
- devel
|
||||
- v*
|
||||
|
||||
concurrency:
|
||||
# Terminate all previous runs of the same workflow for the same tag, but never
|
||||
# cancel for the main / release branch pipelines.
|
||||
group: ci-${{ (github.ref_type == 'tag' && github.ref) || github.run_id }}
|
||||
# TODO: Enable this once https://github.com/orgs/community/discussions/13015 is solved
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check
|
||||
if: startsWith(github.ref, 'refs/heads/')
|
||||
uses: ./.github/workflows/check.yaml
|
||||
secrets:
|
||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
@@ -27,7 +16,6 @@ jobs:
|
||||
|
||||
docs:
|
||||
name: Docs
|
||||
if: startsWith(github.ref, 'refs/heads/')
|
||||
uses: ./.github/workflows/docs.yaml
|
||||
secrets:
|
||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
@@ -35,7 +23,6 @@ jobs:
|
||||
|
||||
test:
|
||||
name: Test
|
||||
if: startsWith(github.ref, 'refs/heads/')
|
||||
uses: ./.github/workflows/test.yaml
|
||||
secrets:
|
||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
@@ -49,94 +36,28 @@ jobs:
|
||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
|
||||
|
||||
arm:
|
||||
name: Build / Cabal - aarch64 GHC 9.4.8
|
||||
if: vars.SSH_ARM_ENABLED
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
remotepath: ${{ steps.Remote-Dir.outputs.remotepath }}
|
||||
env:
|
||||
GITHUB_COMMIT: ${{ github.sha }}
|
||||
GHC_VERSION: '9.4.8'
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- id: Remote-Dir
|
||||
name: Unique directory name for the remote build
|
||||
run: echo "remotepath=postgrest-build-$(uuidgen)" >> "$GITHUB_OUTPUT"
|
||||
- name: Copy script files to the remote server
|
||||
uses: appleboy/scp-action@master
|
||||
with:
|
||||
host: ${{ secrets.SSH_ARM_HOST }}
|
||||
username: ubuntu
|
||||
key: ${{ secrets.SSH_ARM_PRIVATE_KEY }}
|
||||
fingerprint: ${{ secrets.SSH_ARM_FINGERPRINT }}
|
||||
source: ".github/scripts/arm/*"
|
||||
target: ${{ steps.Remote-Dir.outputs.remotepath }}
|
||||
strip_components: 3
|
||||
- name: Build ARM
|
||||
uses: appleboy/ssh-action@master
|
||||
env:
|
||||
REMOTE_DIR: ${{ steps.Remote-Dir.outputs.remotepath }}
|
||||
with:
|
||||
host: ${{ secrets.SSH_ARM_HOST }}
|
||||
username: ubuntu
|
||||
key: ${{ secrets.SSH_ARM_PRIVATE_KEY }}
|
||||
fingerprint: ${{ secrets.SSH_ARM_FINGERPRINT }}
|
||||
command_timeout: 120m
|
||||
script_stop: true
|
||||
envs: GITHUB_COMMIT,REMOTE_DIR,GHC_VERSION
|
||||
script: bash ~/$REMOTE_DIR/build.sh "$GITHUB_COMMIT" "$REMOTE_DIR" "$GHC_VERSION"
|
||||
- name: Download binaries from remote server
|
||||
uses: nicklasfrahm/scp-action@main
|
||||
with:
|
||||
direction: download
|
||||
host: ${{ secrets.SSH_ARM_HOST }}
|
||||
username: ubuntu
|
||||
key: ${{ secrets.SSH_ARM_PRIVATE_KEY }}
|
||||
fingerprint: ${{ secrets.SSH_ARM_FINGERPRINT }}
|
||||
source: "${{ steps.Remote-Dir.outputs.remotepath }}/result.tar.xz"
|
||||
target: "result.tar.xz"
|
||||
- name: Extract downloaded binaries
|
||||
run: tar -xvf result.tar.xz && rm result.tar.xz
|
||||
- name: Save aarch64 executable as artifact
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: postgrest-ubuntu-aarch64
|
||||
path: result/postgrest
|
||||
if-no-files-found: error
|
||||
|
||||
|
||||
tag:
|
||||
name: Release / Tag
|
||||
name: Tag
|
||||
concurrency:
|
||||
# Never tag outdated commits on the main branch by skipping superseded commits
|
||||
group: ci-tag-${{ (github.ref == 'refs/heads/main' && github.ref) || github.run_id }}
|
||||
# TODO: Enable this once https://github.com/orgs/community/discussions/13015 is solved
|
||||
cancel-in-progress: false
|
||||
if: |
|
||||
vars.RELEASE_ENABLED &&
|
||||
startsWith(github.ref, 'refs/heads/') &&
|
||||
needs.docs.result == 'success' &&
|
||||
needs.test.result == 'success' &&
|
||||
needs.build.result == 'success' &&
|
||||
(needs.arm.result == 'skipped' || success())
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-22.04
|
||||
if: vars.RELEASE_ENABLED
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- docs
|
||||
- test
|
||||
- build
|
||||
- arm
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ssh-key: ${{ secrets.POSTGREST_SSH_KEY }}
|
||||
- name: Tag latest commit
|
||||
run: |
|
||||
cabal_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
|
||||
|
||||
if [[ "$cabal_version" == *.*.* ]]; then
|
||||
if [[ "$cabal_version" == *.* ]]; then
|
||||
git fetch --tags
|
||||
|
||||
if [ -z "$(git tag --list "v$cabal_version")" ]; then
|
||||
@@ -147,216 +68,3 @@ jobs:
|
||||
git tag -f "devel"
|
||||
git push -f origin "devel"
|
||||
fi
|
||||
|
||||
|
||||
prepare:
|
||||
name: Release / Prepare
|
||||
if: |
|
||||
startsWith(github.ref, 'refs/tags/') &&
|
||||
needs.build.result == 'success' &&
|
||||
(needs.arm.result == 'skipped' || success())
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- build
|
||||
- arm
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Check the version to be released
|
||||
run: |
|
||||
cabal_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
|
||||
|
||||
if [ "${GITHUB_REF_NAME}" != "devel" ] && [ "${GITHUB_REF_NAME}" != "v$cabal_version" ]; then
|
||||
echo "Tagged version ($GITHUB_REF_NAME) does not match the one in postgrest.cabal (v$cabal_version). Aborting release..."
|
||||
exit 1
|
||||
fi
|
||||
- name: Identify changes from CHANGELOG.md
|
||||
run: |
|
||||
if [ "${GITHUB_REF_NAME}" == "devel" ]; then
|
||||
echo "Getting unreleased changes..."
|
||||
sed -n "1,/## Unreleased/d;/## \[/q;p" CHANGELOG.md > CHANGES.md
|
||||
else
|
||||
version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
|
||||
echo "Propper release, getting changes for version $version ..."
|
||||
sed -n "1,/## \[$version\]/d;/## \[/q;p" CHANGELOG.md > CHANGES.md
|
||||
fi
|
||||
|
||||
echo "Relevant extract from CHANGELOG.md:"
|
||||
cat CHANGES.md
|
||||
- name: Save CHANGES.md as artifact
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: release-changes
|
||||
path: CHANGES.md
|
||||
if-no-files-found: error
|
||||
|
||||
|
||||
github:
|
||||
name: Release / GitHub
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- prepare
|
||||
if: success() || needs.prepare.result == 'success'
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Create release bundle with archives for all builds
|
||||
run: |
|
||||
find artifacts -type f -iname postgrest -exec chmod +x {} \;
|
||||
|
||||
mkdir -p release-bundle
|
||||
|
||||
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-linux-static-x64.tar.xz" \
|
||||
-C artifacts/postgrest-linux-static-x64 postgrest
|
||||
|
||||
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-macos-x64.tar.xz" \
|
||||
-C artifacts/postgrest-macos-x64 postgrest
|
||||
|
||||
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-freebsd-x64.tar.xz" \
|
||||
-C artifacts/postgrest-freebsd-x64 postgrest
|
||||
|
||||
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-ubuntu-aarch64.tar.xz" \
|
||||
-C artifacts/postgrest-ubuntu-aarch64 postgrest
|
||||
|
||||
zip "release-bundle/postgrest-${GITHUB_REF_NAME}-windows-x64.zip" \
|
||||
artifacts/postgrest-windows-x64/postgrest.exe
|
||||
|
||||
- name: Save release bundle
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: release-bundle
|
||||
path: release-bundle
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Publish release on GitHub
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
echo "Releasing version ${GITHUB_REF_NAME} on GitHub..."
|
||||
|
||||
if [ "${GITHUB_REF_NAME}" == "devel" ]; then
|
||||
# To replace the existing release, we must first delete the old assets,
|
||||
# then modify the release, then add the new assets.
|
||||
gh release view devel --json assets \
|
||||
| jq -r '.assets[] | .name' \
|
||||
| xargs -rn1 \
|
||||
gh release delete-asset -y devel
|
||||
gh release edit devel \
|
||||
-t devel \
|
||||
--verify-tag \
|
||||
-F artifacts/release-changes/CHANGES.md \
|
||||
--prerelease
|
||||
gh release upload --clobber devel release-bundle/*
|
||||
else
|
||||
gh release create "${GITHUB_REF_NAME}" \
|
||||
-t "${GITHUB_REF_NAME}" \
|
||||
--verify-tag \
|
||||
-F artifacts/release-changes/CHANGES.md \
|
||||
release-bundle/*
|
||||
fi
|
||||
|
||||
|
||||
docker:
|
||||
name: Release / Docker Hub
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- prepare
|
||||
if: |
|
||||
vars.DOCKER_REPO && vars.DOCKER_USER &&
|
||||
(success() || needs.prepare.result == 'success')
|
||||
env:
|
||||
DOCKER_REPO: ${{ vars.DOCKER_REPO }}
|
||||
DOCKER_USER: ${{ vars.DOCKER_USER }}
|
||||
DOCKER_PASS: ${{ secrets.DOCKER_PASS }}
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Download Docker image
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
|
||||
with:
|
||||
name: postgrest-docker-x64
|
||||
- name: Publish images on Docker Hub
|
||||
run: |
|
||||
docker login -u "$DOCKER_USER" -p "$DOCKER_PASS"
|
||||
docker load -i postgrest-docker.tar.gz
|
||||
|
||||
docker tag postgrest:latest "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}"
|
||||
docker push "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}"
|
||||
|
||||
# Only tag 'latest' for full releases
|
||||
if [ "${GITHUB_REF_NAME}" != "devel" ]; then
|
||||
echo "Pushing to 'latest' tag for full release of ${GITHUB_REF_NAME} ..."
|
||||
docker tag postgrest:latest "$DOCKER_REPO"/postgrest:latest
|
||||
docker push "$DOCKER_REPO"/postgrest:latest
|
||||
else
|
||||
echo "Skipping push to 'latest' tag for pre-release..."
|
||||
fi
|
||||
|
||||
|
||||
docker-description:
|
||||
name: Release / Docker Hub Description
|
||||
runs-on: ubuntu-22.04
|
||||
if: |
|
||||
vars.DOCKER_REPO && vars.DOCKER_USER &&
|
||||
github.ref == 'refs/tags/devel'
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: peter-evans/dockerhub-description@e98e4d1628a5f3be2be7c231e50981aee98723ae # v4.0.0
|
||||
with:
|
||||
username: ${{ vars.DOCKER_USER }}
|
||||
password: ${{ secrets.DOCKER_PASS }}
|
||||
repository: ${{ vars.DOCKER_REPO }}/postgrest
|
||||
short-description: ${{ github.event.repository.description }}
|
||||
readme-filepath: ./docker-hub-readme.md
|
||||
|
||||
|
||||
docker-arm:
|
||||
name: Release / Docker Hub Arm
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- arm
|
||||
- docker
|
||||
env:
|
||||
GITHUB_COMMIT: ${{ github.sha }}
|
||||
DOCKER_REPO: ${{ vars.DOCKER_REPO }}
|
||||
DOCKER_USER: ${{ vars.DOCKER_USER }}
|
||||
DOCKER_PASS: ${{ secrets.DOCKER_PASS }}
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Publish images for ARM builds on Docker Hub
|
||||
uses: appleboy/ssh-action@master
|
||||
env:
|
||||
REMOTE_DIR: ${{ needs.arm.outputs.remotepath }}
|
||||
with:
|
||||
host: ${{ secrets.SSH_ARM_HOST }}
|
||||
username: ubuntu
|
||||
key: ${{ secrets.SSH_ARM_PRIVATE_KEY }}
|
||||
fingerprint: ${{ secrets.SSH_ARM_FINGERPRINT }}
|
||||
script_stop: true
|
||||
envs: GITHUB_COMMIT,DOCKER_REPO,DOCKER_USER,DOCKER_PASS,REMOTE_DIR,GITHUB_REF_NAME
|
||||
script: bash ~/$REMOTE_DIR/docker-publish.sh "$GITHUB_COMMIT" "$DOCKER_REPO" "$DOCKER_USER" "$DOCKER_PASS" "$REMOTE_DIR" "$GITHUB_REF_NAME"
|
||||
|
||||
|
||||
clean-arm:
|
||||
name: Build / Cleanup
|
||||
needs:
|
||||
- arm
|
||||
- docker-arm
|
||||
if: ${{ always() && vars.SSH_ARM_ENABLED }}
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
REMOTE_DIR: ${{ needs.arm.outputs.remotepath }}
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Remove uploaded files from server
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
host: ${{ secrets.SSH_ARM_HOST }}
|
||||
username: ubuntu
|
||||
key: ${{ secrets.SSH_ARM_PRIVATE_KEY }}
|
||||
fingerprint: ${{ secrets.SSH_ARM_FINGERPRINT }}
|
||||
envs: REMOTE_DIR
|
||||
script: rm -rf $REMOTE_DIR
|
||||
|
||||
@@ -25,9 +25,9 @@ concurrency:
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Nix Environment
|
||||
uses: ./.github/actions/setup-nix
|
||||
with:
|
||||
@@ -39,9 +39,9 @@ jobs:
|
||||
|
||||
spellcheck:
|
||||
name: Spellcheck
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Nix Environment
|
||||
uses: ./.github/actions/setup-nix
|
||||
with:
|
||||
@@ -51,17 +51,3 @@ jobs:
|
||||
run: postgrest-docs-spellcheck
|
||||
- name: Run dictcheck
|
||||
run: postgrest-docs-dictcheck
|
||||
|
||||
|
||||
linkcheck:
|
||||
name: Linkcheck
|
||||
if: github.base_ref == 'main'
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Setup Nix Environment
|
||||
uses: ./.github/actions/setup-nix
|
||||
with:
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
tools: docs.linkcheck.bin
|
||||
- run: postgrest-docs-linkcheck
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
name: Linkcheck
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '1 2 * * 3'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
linkcheck:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Nix Environment
|
||||
uses: ./.github/actions/setup-nix
|
||||
with:
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
tools: docs.linkcheck.bin
|
||||
- run: postgrest-docs-linkcheck
|
||||
@@ -0,0 +1,205 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- devel
|
||||
- v*
|
||||
|
||||
concurrency:
|
||||
# Terminate all previous runs of the same workflow for the same tag.
|
||||
group: release-${{ github.ref }}
|
||||
# TODO: Enable this once https://github.com/orgs/community/discussions/13015 is solved
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
uses: ./.github/workflows/build.yaml
|
||||
secrets:
|
||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
|
||||
|
||||
prepare:
|
||||
name: Prepare
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- build
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Check the version to be released
|
||||
run: |
|
||||
cabal_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
|
||||
|
||||
if [ "${GITHUB_REF_NAME}" != "devel" ] && [ "${GITHUB_REF_NAME}" != "v$cabal_version" ]; then
|
||||
echo "Tagged version ($GITHUB_REF_NAME) does not match the one in postgrest.cabal (v$cabal_version). Aborting release..."
|
||||
exit 1
|
||||
fi
|
||||
- name: Identify changes from CHANGELOG.md
|
||||
run: |
|
||||
if [ "${GITHUB_REF_NAME}" == "devel" ]; then
|
||||
echo "Getting unreleased changes..."
|
||||
sed -n "1,/## Unreleased/d;/## \[/q;p" CHANGELOG.md > CHANGES.md
|
||||
else
|
||||
version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
|
||||
echo "Propper release, getting changes for version $version ..."
|
||||
sed -n "1,/## \[$version\]/d;/## \[/q;p" CHANGELOG.md > CHANGES.md
|
||||
fi
|
||||
|
||||
echo "Relevant extract from CHANGELOG.md:"
|
||||
cat CHANGES.md
|
||||
- name: Save CHANGES.md as artifact
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: release-changes
|
||||
path: CHANGES.md
|
||||
if-no-files-found: error
|
||||
|
||||
|
||||
github:
|
||||
name: GitHub
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- prepare
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Create release bundle with archives for all builds
|
||||
run: |
|
||||
find artifacts -type f -iname postgrest -exec chmod +x {} \;
|
||||
|
||||
mkdir -p release-bundle
|
||||
|
||||
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-linux-static-x86-64.tar.xz" \
|
||||
-C artifacts/postgrest-linux-static-x86-64 postgrest
|
||||
|
||||
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-macos-aarch64.tar.xz" \
|
||||
-C artifacts/postgrest-macos-aarch64 postgrest
|
||||
|
||||
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-macos-x86-64.tar.xz" \
|
||||
-C artifacts/postgrest-macos-x86-64 postgrest
|
||||
|
||||
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-freebsd-x86-64.tar.xz" \
|
||||
-C artifacts/postgrest-freebsd-x86-64 postgrest
|
||||
|
||||
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-ubuntu-aarch64.tar.xz" \
|
||||
-C artifacts/postgrest-ubuntu-aarch64 postgrest
|
||||
|
||||
zip --junk-paths "release-bundle/postgrest-${GITHUB_REF_NAME}-windows-x86-64.zip" \
|
||||
artifacts/postgrest-windows-x86-64/postgrest.exe
|
||||
|
||||
- name: Save release bundle
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: release-bundle
|
||||
path: release-bundle
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Publish release on GitHub
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
echo "Releasing version ${GITHUB_REF_NAME} on GitHub..."
|
||||
|
||||
if [ "${GITHUB_REF_NAME}" == "devel" ]; then
|
||||
# To replace the existing release, we must first delete the old assets,
|
||||
# then modify the release, then add the new assets.
|
||||
gh release view devel --json assets \
|
||||
| jq -r '.assets[] | .name' \
|
||||
| xargs -rn1 \
|
||||
gh release delete-asset -y devel
|
||||
gh release edit devel \
|
||||
-t devel \
|
||||
--verify-tag \
|
||||
-F artifacts/release-changes/CHANGES.md \
|
||||
--prerelease
|
||||
gh release upload --clobber devel release-bundle/*
|
||||
else
|
||||
gh release create "${GITHUB_REF_NAME}" \
|
||||
-t "${GITHUB_REF_NAME}" \
|
||||
--verify-tag \
|
||||
-F artifacts/release-changes/CHANGES.md \
|
||||
release-bundle/*
|
||||
fi
|
||||
|
||||
|
||||
docker:
|
||||
name: Docker Hub
|
||||
runs-on: ubuntu-24.04-arm
|
||||
needs:
|
||||
- prepare
|
||||
if: |
|
||||
vars.DOCKER_REPO && vars.DOCKER_USER
|
||||
env:
|
||||
DOCKER_REPO: ${{ vars.DOCKER_REPO }}
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Download x86-64 Docker image
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: postgrest-docker-x86-64
|
||||
- name: Download aarch64 binary
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: postgrest-ubuntu-aarch64
|
||||
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
- uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
with:
|
||||
username: ${{ vars.DOCKER_USER }}
|
||||
password: ${{ secrets.DOCKER_PASS }}
|
||||
- name: Build aarch64 Docker image
|
||||
run: |
|
||||
# This only pushes the image via digest, not a tag. This will not appear
|
||||
# in the image list on Docker Hub, yet. It will be later added to the main
|
||||
# tag's manifest.
|
||||
docker buildx build \
|
||||
-t "$DOCKER_REPO/postgrest" \
|
||||
--platform linux/arm64 \
|
||||
--output push-by-digest=true,type=image,push=true \
|
||||
--metadata-file metadata.json \
|
||||
.
|
||||
echo "SHA256_ARM=$(jq -r '."containerimage.digest"' metadata.json)" >> "$GITHUB_ENV"
|
||||
- name: Publish images on Docker Hub
|
||||
run: |
|
||||
docker load -i postgrest-docker.tar.gz
|
||||
|
||||
docker tag postgrest:latest "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}"
|
||||
docker push "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}"
|
||||
docker buildx imagetools create --append \
|
||||
-t "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}" \
|
||||
"$DOCKER_REPO/postgrest@$SHA256_ARM"
|
||||
|
||||
# Only tag 'latest' for full releases
|
||||
if [ "${GITHUB_REF_NAME}" != "devel" ]; then
|
||||
echo "Pushing to 'latest' tag for full release of ${GITHUB_REF_NAME} ..."
|
||||
docker tag postgrest:latest "$DOCKER_REPO"/postgrest:latest
|
||||
docker push "$DOCKER_REPO"/postgrest:latest
|
||||
docker buildx imagetools create --append \
|
||||
-t "$DOCKER_REPO/postgrest:latest" \
|
||||
"$DOCKER_REPO/postgrest@$SHA256_ARM"
|
||||
else
|
||||
echo "Skipping push to 'latest' tag for pre-release..."
|
||||
fi
|
||||
|
||||
|
||||
docker-description:
|
||||
name: Docker Hub Description
|
||||
runs-on: ubuntu-24.04
|
||||
if: |
|
||||
vars.DOCKER_REPO && vars.DOCKER_USER &&
|
||||
github.ref == 'refs/tags/devel'
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5.0.0
|
||||
with:
|
||||
username: ${{ vars.DOCKER_USER }}
|
||||
password: ${{ secrets.DOCKER_PASS }}
|
||||
repository: ${{ vars.DOCKER_REPO }}/postgrest
|
||||
short-description: ${{ github.event.repository.description }}
|
||||
readme-filepath: ./docker-hub-readme.md
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
name: Upload Reports
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- CI
|
||||
- Test
|
||||
branches-ignore:
|
||||
- devel
|
||||
- v[0-9]+
|
||||
- v[0-9]+.[0-9]+.[0-9]+
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
loadtest:
|
||||
name: Loadtest
|
||||
permissions:
|
||||
checks: write
|
||||
runs-on: ubuntu-22.04
|
||||
if: github.event.workflow_run.conclusion == 'success' || github.event.workflow_run.conclusion == 'failure'
|
||||
steps:
|
||||
- name: Download from Artifacts
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
name: loadtest.md
|
||||
path: artifacts
|
||||
- name: Upload to GitHub Checks
|
||||
uses: LouisBrunner/checks-action@6b626ffbad7cc56fd58627f774b9067e6118af23 # v2.0.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
sha: ${{ github.event.workflow_run.head_sha }}
|
||||
name: Loadtest Results
|
||||
conclusion: neutral
|
||||
output: |
|
||||
{"summary":""}
|
||||
output_text_description_file: artifacts/loadtest.md
|
||||
@@ -32,24 +32,26 @@ concurrency:
|
||||
jobs:
|
||||
coverage:
|
||||
name: Coverage
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
# Hack for enabling color output, see:
|
||||
# https://github.com/actions/runner/issues/241#issuecomment-842566950
|
||||
shell: script -qec "bash --noprofile --norc -eo pipefail {0}"
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Nix Environment
|
||||
uses: ./.github/actions/setup-nix
|
||||
with:
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
tools: tests.coverage.bin tests.testDoctests.bin tests.testSpecIdempotence.bin
|
||||
tools: tests.coverage.bin tests.testDoctests.bin tests.testSpecIdempotence.bin cabalTools.update.bin
|
||||
|
||||
- run: postgrest-cabal-update
|
||||
|
||||
- name: Run coverage (IO tests and Spec tests against PostgreSQL 15)
|
||||
run: postgrest-coverage
|
||||
- name: Upload coverage to codecov
|
||||
uses: codecov/codecov-action@125fc84a9a348dbcf27191600683ec096ec9021c # v4.4.1
|
||||
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
|
||||
with:
|
||||
files: ./coverage/codecov.json
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
@@ -67,72 +69,107 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pgVersion: ["9_6", 10, 11, 12, 13, 14, 15, 16]
|
||||
pgVersion: [13, 14, 15, 16, 17]
|
||||
name: PG ${{ matrix.pgVersion }}
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
# Hack for enabling color output, see:
|
||||
# https://github.com/actions/runner/issues/241#issuecomment-842566950
|
||||
shell: script -qec "bash --noprofile --norc -eo pipefail {0}"
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Nix Environment
|
||||
uses: ./.github/actions/setup-nix
|
||||
with:
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
tools: tests.testSpec.bin tests.testIO.bin tests.testBigSchema.bin withTools.postgresql-${{ matrix.pgVersion }}.bin
|
||||
tools: tests.testSpec.bin tests.testObservability.bin tests.testIO.bin tests.testBigSchema.bin withTools.pg-${{ matrix.pgVersion }}.bin cabalTools.update.bin
|
||||
|
||||
- run: postgrest-cabal-update
|
||||
|
||||
- name: Run spec tests
|
||||
if: always()
|
||||
run: postgrest-with-postgresql-${{ matrix.pgVersion }} postgrest-test-spec
|
||||
run: postgrest-with-pg-${{ matrix.pgVersion }} postgrest-test-spec
|
||||
|
||||
- name: Run observability tests
|
||||
if: always()
|
||||
run: postgrest-with-pg-${{ matrix.pgVersion }} postgrest-test-observability
|
||||
|
||||
- name: Run IO tests
|
||||
if: always()
|
||||
run: postgrest-with-postgresql-${{ matrix.pgVersion }} postgrest-test-io -vv
|
||||
run: postgrest-with-pg-${{ matrix.pgVersion }} postgrest-test-io -vv
|
||||
|
||||
- name: Run IO tests on a big schema
|
||||
if: always()
|
||||
run: postgrest-with-postgresql-${{ matrix.pgVersion }} postgrest-test-big-schema -vv
|
||||
run: postgrest-with-pg-${{ matrix.pgVersion }} postgrest-test-big-schema -vv
|
||||
|
||||
|
||||
memory:
|
||||
name: Memory
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Nix Environment
|
||||
uses: ./.github/actions/setup-nix
|
||||
with:
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
tools: memory.test.bin
|
||||
tools: tests.testMemory.bin cabalTools.update.bin
|
||||
|
||||
- run: postgrest-cabal-update
|
||||
|
||||
- name: Run memory tests
|
||||
run: postgrest-test-memory
|
||||
|
||||
|
||||
loadtest:
|
||||
strategy:
|
||||
matrix:
|
||||
kind: ['mixed', 'jwt-hs', 'jwt-hs-cache', 'jwt-hs-cache-worst', 'jwt-rsa', 'jwt-rsa-cache', 'jwt-rsa-cache-worst']
|
||||
name: Loadtest
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Nix Environment
|
||||
uses: ./.github/actions/setup-nix
|
||||
with:
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
tools: loadtest.loadtestAgainst.bin loadtest.report.bin
|
||||
- uses: WyriHaximus/github-action-get-previous-tag@04e8485ecb6487243907e330d522ff60f02283ce # v1.4.0
|
||||
id: get-latest-tag
|
||||
with:
|
||||
prefix: v
|
||||
tools: loadtest.loadtestAgainst.bin loadtest.report.bin cabalTools.update.bin
|
||||
|
||||
- run: postgrest-cabal-update
|
||||
|
||||
- name: Run loadtest
|
||||
env:
|
||||
TARGET_BRANCH: ${{ github.base_ref || github.ref_name }}
|
||||
run: |
|
||||
postgrest-loadtest-against main ${{ steps.get-latest-tag.outputs.tag }}
|
||||
postgrest-loadtest-report > loadtest/loadtest.md
|
||||
- name: Upload report
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
if [ "$TARGET_BRANCH" = "main" ]; then
|
||||
latest_tag=$(git tag --sort=-creatordate --list "v*" | head -n1)
|
||||
else
|
||||
latest_tag=$(git tag --merged HEAD --sort=-creatordate "v*" | head -n1)
|
||||
fi
|
||||
postgrest-loadtest-against -k ${{ matrix.kind }} "$TARGET_BRANCH" "$latest_tag"
|
||||
postgrest-loadtest-report -g ${{ matrix.kind }} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
flake:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
runs-on:
|
||||
- macos-15-intel # x86_64-darwin
|
||||
- macos-14 # aarch64-darwin
|
||||
- ubuntu-24.04 # x86_64-linux
|
||||
- ubuntu-24.04-arm # aarch64-linux
|
||||
name: Flake Check
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
name: loadtest.md
|
||||
path: loadtest/loadtest.md
|
||||
if-no-files-found: error
|
||||
fetch-depth: 0
|
||||
- name: Setup Nix Environment
|
||||
uses: ./.github/actions/setup-nix
|
||||
with:
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
- name: Run flake check
|
||||
run: |
|
||||
nix flake check
|
||||
|
||||
@@ -14,7 +14,7 @@ site
|
||||
.#*
|
||||
*.swp
|
||||
result*
|
||||
dist-newstyle
|
||||
dist-*
|
||||
postgrest.hp
|
||||
postgrest.prof
|
||||
__pycache__
|
||||
@@ -24,3 +24,5 @@ coverage
|
||||
loadtest
|
||||
.history
|
||||
.docs-build
|
||||
gen_targets.http
|
||||
gen_jwk.json
|
||||
|
||||
@@ -5,6 +5,6 @@ python:
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
os: ubuntu-24.04
|
||||
tools:
|
||||
python: "3.11"
|
||||
|
||||
@@ -13,31 +13,26 @@ PostgREST ongoing development is only possible thanks to our Sponsors and Backer
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://gnuhost.eu/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="static/gnuhost.png">
|
||||
<a href="https://supabase.io?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage" target="_blank">
|
||||
<img width="296px" src="static/supabase.svg">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="static/neon.jpg">
|
||||
<a href="https://www.euronodes.com/postgrest" target="_blank">
|
||||
<img width="296px" src="static/euronodes.svg">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="static/code-build.png">
|
||||
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="static/neon.jpg">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://supabase.io?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage" target="_blank">
|
||||
<img width="296px" src="static/supabase.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="static/tembo.png">
|
||||
<a href="https://www.bytebase.com/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="static/bytebase.svg">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -93,6 +88,16 @@ PostgREST ongoing development is only possible thanks to our Sponsors and Backer
|
||||
<img width="222px" src="static/oblivious.jpg">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="222px" src="static/code-build.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="static/tembo.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -1,10 +1,334 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
All notable changes to this project will be documented in this file. From version `14.0` onwards PostgREST follows a `MAJOR.PATCH` two-part versioning. Only even-numbered MAJOR versions will be released, reserving odd-numbered MAJOR versions for development.
|
||||
|
||||
## Unreleased
|
||||
|
||||
## [14.11] - 2026-05-04
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix login with uppercase and mixed case role names by @taimoorzaeem in #4678
|
||||
- Restore Listener query shape so it can be found in `pg_stat_activity` by @mkleczek in #4857 #4859
|
||||
- The LISTEN channel now automatically recovers when it stops working due to a PostgreSQL bug @laurenceisla in #3147
|
||||
- Fix misleading "Functions" name on schema cache summary in startup logs by @taimoorzaeem in #4821
|
||||
|
||||
## [14.10] - 2026-04-16
|
||||
|
||||
### Added
|
||||
|
||||
- Log when the pool is released during schema cache reload on `log-level=debug` by @mkleczek in #4668
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix unnecessary connection pool flushes during schema cache reloading by @mkleczek in #4645
|
||||
|
||||
## [14.9] - 2026-04-10
|
||||
|
||||
### Added
|
||||
|
||||
- Log host, port and pg version of listener database connection by @mkleczek in #4617 #4618
|
||||
|
||||
### Fixed
|
||||
|
||||
- Remove red herring warp logs on default log-level, only emit them on `log-level=debug` by @steve-chavez in #4799
|
||||
|
||||
## [14.8] - 2026-04-03
|
||||
|
||||
### Added
|
||||
|
||||
- Log a `HINT` when the LISTEN channel stops working due to a PostgreSQL bug by @laurenceisla in #4581
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix invalid OpenAPI 2.0 format for integer types (`smallint`, `integer`, `bigint`) by @arturbent0 in #4641
|
||||
|
||||
## [14.7] - 2026-03-20
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix not logging SIGTERM and SIGINT by @steve-chavez in #4728
|
||||
|
||||
## [14.6] - 2026-03-06
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix leaking table and function names when calculating error hint by @taimoorzaeem in #4675
|
||||
|
||||
## [14.5] - 2026-02-12
|
||||
|
||||
### Fixed
|
||||
|
||||
- Don't hide async exceptions in logs by @stevechavez in #4646
|
||||
|
||||
## [14.4] - 2026-01-29
|
||||
|
||||
### Fixed
|
||||
|
||||
- Ensure Listener connections are released by @mkleczek in #4614
|
||||
- Fix incorrectly filtering the returned representation for PATCH requests when using `or/and` filters by @laurenceisla in #3707
|
||||
- Fix listener running with exception masked after first failure by @mkleczek #4615
|
||||
|
||||
## [14.3] - 2026-01-03
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix performance and high memory usage of relation hint calculation by @mkleczek in #4462, #4463
|
||||
|
||||
## [14.2] - 2025-12-18
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix `hasSingleUnnamedParam` incorrectly matching functions with named parameters by @joelonsql in #4553
|
||||
+ Functions with a single named parameter (e.g., `foo(data json)`) no longer incorrectly match the single-param fallback, returning a clean `PGRST202` error instead of a confusing PostgreSQL `42883` error.
|
||||
- Fix misleading logs on unsupported PostgreSQL versions by @taimoorzaeem in #4519
|
||||
- Fix regression where the `PGRST103` error response was truncated by @laurenceisla in #4455
|
||||
+ Happened when an `offset` was greater than the rows requested and `Prefer: count=exact` was sent.
|
||||
- Fix not returning `Content-Length` on empty HTTP `201` responses by @laurenceisla in #4518
|
||||
- Fix inaccurate Server-Timing header durations by @steve-chavez in #4522
|
||||
- Fix inaccurate "Schema cache queried" logs by @steve-chavez in #4522
|
||||
|
||||
## [14.1] - 2025-11-05
|
||||
|
||||
## Fixed
|
||||
|
||||
- Fix `db-pre-config` function failing when function names are pg reserved words by @taimoorzaeem in #4380
|
||||
- Fix `server-host=!6` incorrectly binds to IPv4 address by @taimoorzaeem in #3202
|
||||
|
||||
## [14.0] - 2025-10-24
|
||||
|
||||
### Added
|
||||
|
||||
- Bounded JWT cache using the SIEVE algorithm by @mkleczek in #4084
|
||||
+ It now uses a fixed size cache instead of arbitrary sized cache.
|
||||
- Add `--ready` flag for postgrest healthcheck by @taimoorzaeem in #4239
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix not logging OpenAPI queries when `log-query=main-query` is enabled by @steve-chavez in #4226
|
||||
- Fix not logging explain query when `log-query=main-query` is enabled by @steve-chavez in #4319
|
||||
- Fix not logging transaction variables and db-pre-request function when `log-query=main-query` is enabled by @steve-chavez in #3934
|
||||
- Fix not logging the JSON message to stderr on a `PGRST002` error by @laurenceisla in #4129
|
||||
- Fix reloading the Schema Cache unnecessarily on a `PGRST002` error by @laurenceisla in #4367
|
||||
- Fix schema cache loading taking a long time for large schemas by @mkleczek in #4360, #3704
|
||||
|
||||
### Changed
|
||||
|
||||
- Drop support for PostgreSQL EOL version 12 by @wolfgangwalther in #3865
|
||||
- From now on PostgREST will follow a `MAJOR.PATCH` two-part versioning. Only even-numbered MAJOR versions will be released, reserving odd-numbered MAJOR versions for development.
|
||||
- Replaced `jwt-cache-max-lifetime` config with `jwt-cache-max-entries` by @mkleczek in #4084
|
||||
- `log-query` config now takes a boolean instead of a string value by @steve-chavez in #3934
|
||||
|
||||
## [13.0.8] - 2025-10-24
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix loading utf-8 config files with `ASCII` locale set by @taimoorzaeem in #4386
|
||||
|
||||
## [13.0.7] - 2025-09-14
|
||||
|
||||
### Added
|
||||
|
||||
- Improve the `PGRST106` error when the requested schema is invalid by @laurenceisla in #4089
|
||||
+ It now shows the invalid schema in the `message` field.
|
||||
+ The exposed schemas are now listed in the `hint` instead of the `message` field.
|
||||
- Improve error details of `PGRST301` error by @taimoorzaeem in #4051
|
||||
|
||||
## [13.0.6] - 2025-08-30
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix logging the Haskell type instead of the listener error message directly by @laurenceisla in #3588
|
||||
- Fix format of `IPv6` address logged at PostgREST startup by @taimoorzaeem in #4291
|
||||
- Fix empty enum in `preferParams` OpenAPI parameter by @laurenceisla in #4292
|
||||
|
||||
## [13.0.5] - 2025-08-24
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix OpenAPI broken docs link by @taimoorzaeem in #4080
|
||||
- Fix OpenAPI specification incorrectly exposing GET methods for volatile functions by @joelonsql in #4174
|
||||
- Fix empty spread embeddings return unexpected SQL error by @taimoorzaeem in #3887
|
||||
- Fix `/metrics` endpoint not responding with `Content-Type` header by @taimoorzaeem in #4271
|
||||
|
||||
## [13.0.4] - 2025-06-17
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix regression that makes full-text search not work on domain types based on `tsvector` by @laurenceisla in #4135
|
||||
- Fix `jwt-aud` config not failing when set to an invalid URI by @taimoorzaeem in #4132
|
||||
|
||||
## [13.0.3] - 2025-06-16
|
||||
|
||||
- Fix `max-affected` preference not failing with RPC when `handling=strict` by @taimoorzaeem in #4100
|
||||
- Fix a property definition's type in OpenAPI not showing the correct base type of a recursive domain by @laurenceisla in #4136
|
||||
|
||||
### Fixed
|
||||
|
||||
## [13.0.2] - 2025-06-02
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix regression that makes `ORDER BY` with nulls-order not work alongside limits by @laurenceisla in #4109
|
||||
|
||||
## [13.0.1] - 2025-06-01
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix jwt error returning HTTP status `400` for invalid role by @taimoorzaeem in #3601
|
||||
- Fix `db-extra-search-path` cannot be set to nothing by @taimoorzaeem in #4074
|
||||
+ It can now be disabled by setting it to empty string.
|
||||
+ Schema Cache load error is now logged including `db-schemas` and `db-extra-search-path` config values.
|
||||
|
||||
## [13.0.0] - 2025-05-08
|
||||
|
||||
### Added
|
||||
|
||||
- #3558, Add the `admin-server-host` config to set the host for the admin server - @develop7
|
||||
- #3607, Log to stderr when the JWT secret is less than 32 characters long - @laurenceisla
|
||||
- #2858, Performance improvements when calling RPCs via GET using indexes in more cases - @wolfgangwalther
|
||||
- #3560, Log resolved host in "Listening on ..." messages - @develop7
|
||||
- #3727, Log maximum pool size - @steve-chavez
|
||||
- #1536, Add string comparison feature for jwt-role-claim-key - @taimoorzaeem
|
||||
- #3747, Allow `not_null` value for the `is` operator - @taimoorzaeem
|
||||
- #2255, Apply `to_tsvector()` explicitly to the full-text search filtered column (excluding `tsvector` types) - @laurenceisla
|
||||
- #1578, Log the main SQL query to stderr at the current `log-level` when `log-query=main-query` - @laurenceisla
|
||||
- #3903, Log connection pool borrows on `log-level=debug` - @taimoorzaeem
|
||||
- #3041, Allow spreading one-to-many and many-to-many embedded resources - @laurenceisla
|
||||
+ The selected columns in the embedded resources are aggregated into arrays
|
||||
+ Aggregates are not supported
|
||||
- #2967, Add `Proxy-Status` header for better error response - @taimoorzaeem
|
||||
- #4016, Add `Content-Length` response header - @laurenceisla
|
||||
|
||||
### Fixed
|
||||
|
||||
- #3693, Prevent spread embedding to allow aggregates when they are disabled - @laurenceisla
|
||||
- #3693, A nested spread embedding now correctly groups by the fields of its top parent relationship - @laurenceisla
|
||||
- #3693, Fix spread embedding errors when using the `count()` aggregate without a field - @laurenceisla
|
||||
+ Fixed `"column reference <col> is ambiguous"` error when selecting `?select=...table(col,count())`
|
||||
+ Fixed `"column <json_aggregate>.<alias> does not exist"` error when selecting `?select=...table(aias:count())`
|
||||
- #3727, Clarify "listening" logs - @steve-chavez
|
||||
- #3795, Clarify `Accept: vnd.pgrst.object` error message - @steve-chavez
|
||||
- #3697, #3602, Handle queries on non-existing table gracefully - @taimoorzaeem
|
||||
- #3600, #3926, Improve JWT errors - @taimoorzaeem
|
||||
- #3013, Fix `order=` with POST, PATCH, PUT and DELETE requests - @taimoorzaeem
|
||||
- #3965, Fix filter on unselected columns in a table-valued function - @taimoorzaeem
|
||||
- #4052, Fix schema cache load duplicate objects with different object type but same oid - @taimoorzaeem
|
||||
|
||||
### Changed
|
||||
|
||||
- #2052, Dropped support for PostgreSQL 9.6 - @wolfgangwalther
|
||||
- #2052, Dropped support for PostgreSQL 10 - @wolfgangwalther
|
||||
- #2052, Dropped support for PostgreSQL 11 - @wolfgangwalther
|
||||
- #3508, PostgREST now fails to start when `server-port` and `admin-server-port` config options are the same - @develop7
|
||||
- #3607, PostgREST now fails to start when the JWT secret is less than 32 characters long - @laurenceisla
|
||||
- #3644, Fail schema cache lookup with invalid `db-schemas` or `db-extra-search-path` config - @wolfgangwalther
|
||||
- Previously, this would silently return 200 - OK on the root endpoint, but don't provide any usable endpoints.
|
||||
- Note: This also applies when deleting the `public` schema - both config options default to that.
|
||||
- #3757, Remove support for `Prefer: params=single-object` - @joelonsql
|
||||
+ This preference was deprecated in favor of Functions with an array of JSON objects
|
||||
- #3013, Drop support for Limited updates/deletes
|
||||
+ The feature was complicated and largely unused.
|
||||
- #3956, Drop `/config` endpoint of admin server - @steve-chavez
|
||||
+ The endpoint was at risk of being left unprotected when exposing it.
|
||||
+ The accompanying `admin-server-config-enabled` config was also dropped.
|
||||
- #3598, PostgREST now validates the `kid` parameter of the JWT - @wolfgangwalther
|
||||
+ If the JWT contains a ``kid`` parameter, then PostgREST will look for the JSON Web Key in the `jwt-secret`.
|
||||
+ If the JWT doesn't contain a `kid`, the behavior should be backwards compatible. PostgREST will try each key in the `jwt-secret` one by one until it finds one that works.
|
||||
- #3697, #3602, Querying non-existent table now returns `PGRST205` error instead of empty json - @taimoorzaeem
|
||||
- #3600, #3926, Improve JWT errors - @taimoorzaeem
|
||||
+ Return `PGRST301` error when `Bearer` in auth header is sent empty
|
||||
+ Diagnostic error messages instead of exposed internals
|
||||
+ Return new `PGRST303` error when jwt claims decoding fails
|
||||
- #3906, Return `PGRST125` and `PGRST126` errors instead of empty json - @taimoorzaeem
|
||||
|
||||
## [12.2.12] - 2025-05-01
|
||||
|
||||
### Fixed
|
||||
|
||||
- #3956, Fix exposing admin server `/config` by default - @steve-chavez
|
||||
+ The above endpoint is now disabled unless the `admin-server-config-enabled` config is set to `true`
|
||||
|
||||
## [12.2.11] - 2025-04-22
|
||||
|
||||
### Fixed
|
||||
|
||||
- #4030, Fix regression with parameter `charset=utf-8` in mediatype - @taimoorzaeem
|
||||
|
||||
## [12.2.10] - 2025-04-18
|
||||
|
||||
### Fixed
|
||||
|
||||
- #3889, Fix: JWT cache purging on every request decreases performance - @mkleczek
|
||||
|
||||
## [12.2.9] - 2025-04-16
|
||||
|
||||
### Fixed
|
||||
|
||||
- #3498, Fix incorrect parsing of the `for` parameter of the `application/vnd.pgrst.plan` media type - @taimoorzaeem
|
||||
- #4014, Fix JWT cache allows old tokens after the jwt-secret is changed in a config reload - @taimoorzaeem
|
||||
|
||||
## [12.2.8] - 2025-02-10
|
||||
|
||||
### Fixed
|
||||
|
||||
- #3841, Log `503` client error to stderr - @taimoorzaeem
|
||||
|
||||
## [12.2.7] - 2025-02-03
|
||||
|
||||
### Fixed
|
||||
|
||||
- #2524, Fix schema reloading notice on windows - @diogob
|
||||
|
||||
## [12.2.6] - 2025-01-29
|
||||
|
||||
### Fixed
|
||||
|
||||
- #3788, Fix jwt cache does not remove expired entries - @taimoorzaeem
|
||||
|
||||
## [12.2.5] - 2025-01-20
|
||||
|
||||
### Fixed
|
||||
|
||||
- #3867, Fix startup for arm64 docker image - @wolfgangwalther
|
||||
|
||||
## [12.2.4] - 2025-01-18
|
||||
|
||||
### Fixed
|
||||
|
||||
- #3779, Always log the schema cache load time - @steve-chavez
|
||||
- #3706, Fix insert with `missing=default` uses default value of domain instead of column - @taimoorzaeem
|
||||
|
||||
## [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
|
||||
|
||||
- #3093, Nested empty embeds no longer show empty values and are correctly omitted - @laurenceisla
|
||||
- #3644, Make --dump-schema work with in-database pgrst.db_schemas setting - @wolfgangwalther
|
||||
- #3644, Show number of timezones in schema cache load report - @wolfgangwalther
|
||||
- #3644, List correct enum options in OpenApi output when multiple types with same name are present - @wolfgangwalther
|
||||
- #3523, Fix schema cache loading retry without backoff - @steve-chavez
|
||||
|
||||
## [12.2.1] - 2024-06-27
|
||||
|
||||
### Fixed
|
||||
|
||||
- #3147, Don't reload schema cache on every listener failure - @steve-chavez
|
||||
|
||||
### Documentation
|
||||
|
||||
- #3592, Architecture diagram now supports dark mode and has links - @laurenceisla
|
||||
- #3616, The schema isolation diagram now supports dark mode and uses well-known schemas - @laurenceisla
|
||||
|
||||
## [12.2.0] - 2024-06-11
|
||||
|
||||
### Added
|
||||
|
||||
@@ -1,3 +1,55 @@
|
||||
This repository follows the same contribution guidelines as the main PostgREST repository contribution guidelines:
|
||||
# Contributing to PostgREST
|
||||
|
||||
https://github.com/PostgREST/postgrest/blob/main/.github/CONTRIBUTING.md
|
||||
**First:** if you're unsure or afraid of _anything_, just ask or
|
||||
submit the issue or pull request anyways. You won't be yelled at
|
||||
for giving your best effort. The worst that can happen is that
|
||||
you'll be politely asked to change something. We appreciate any
|
||||
sort of contributions, and don't want a wall of rules to get in the
|
||||
way of that.
|
||||
|
||||
However, for those individuals who want a bit more guidance on the
|
||||
best way to contribute to the project, read on. This document will
|
||||
cover what we're looking for. By addressing all the points we're
|
||||
looking for, it raises the chances we can quickly merge or address
|
||||
your contributions.
|
||||
|
||||
## Issues
|
||||
|
||||
For questions on how to use PostgREST, please use
|
||||
[GitHub discussions](https://github.com/PostgREST/postgrest/discussions).
|
||||
|
||||
### Reporting an Issue
|
||||
|
||||
* Make sure you test against the latest [stable release](https://github.com/PostgREST/postgrest/releases/latest)
|
||||
and also against the latest [devel release](https://github.com/PostgREST/postgrest/releases/tag/devel).
|
||||
It is possible we already fixed the bug you're experiencing.
|
||||
|
||||
* Provide steps to reproduce the issue, including your OS version and
|
||||
the specific database schema that you are using.
|
||||
|
||||
* Please include SQL logs for issues involving runtime problems. To obtain logs first
|
||||
[enable logging all statements](http://www.microhowto.info/howto/log_all_queries_to_a_postgresql_server.html),
|
||||
then [find your logs](http://blog.endpoint.com/2014/11/dear-postgresql-where-are-my-logs.html).
|
||||
|
||||
* If your database schema has changed while the PostgREST server is running,
|
||||
[send the server a `SIGUSR1` signal](http://postgrest.org/en/latest/admin.html#schema-reloading) or restart it to ensure the schema cache
|
||||
is not stale. This sometimes fixes apparent bugs.
|
||||
|
||||
## Code
|
||||
|
||||
We have a fully nix-based development environment with many tools for a smooth development workflow available.
|
||||
Check the [development docs](https://github.com/PostgREST/postgrest/blob/main/nix/README.md) on how to set it up and use it.
|
||||
|
||||
### Haskell Conventions
|
||||
|
||||
* All contributions must pass the tests before being merged. When
|
||||
you create a pull request your code will automatically be tested.
|
||||
|
||||
* All code must also pass [hlint](http://community.haskell.org/~ndm/hlint/) and [stylish-haskell](https://github.com/jaspervdj/stylish-haskell)
|
||||
with no warnings. This helps enforce a uniform style for all committers. Continuous integration will check this as well on every
|
||||
pull request. There are useful tools in the nix-shell that help with checking this locally. You can run `postgrest-check` to do this manually but
|
||||
we recommend adding it to `.git/hooks/pre-commit` as `nix-shell --run postgrest-check` to automatically check this before doing a commit.
|
||||
|
||||
### Running Tests
|
||||
|
||||
For instructions on running tests, see the [development docs](https://github.com/PostgREST/postgrest/blob/main/nix/README.md#testing).
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# PostgREST docker hub image
|
||||
# PostgREST Docker Hub image for aarch64.
|
||||
# The x86-64 is a single-static-binary image built via Nix, see:
|
||||
# nix/tools/docker/README.md
|
||||
|
||||
FROM ubuntu:noble@sha256:3f85b7caad41a95462cf5b787d8a04604c8262cdcdf9a472b8c52ef83375fe15 AS postgrest
|
||||
FROM ubuntu:resolute@sha256:5e275723f82c67e387ba9e3c24baa0abdcb268917f276a0561c97bef9450d0b4 AS postgrest
|
||||
|
||||
RUN apt-get update -y \
|
||||
&& apt install -y --no-install-recommends libpq-dev zlib1g-dev jq gcc libnuma-dev \
|
||||
@@ -8,6 +10,7 @@ RUN apt-get update -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY postgrest /usr/bin/postgrest
|
||||
RUN chmod +x /usr/bin/postgrest
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||

|
||||
|
||||
[](https://www.patreon.com/postgrest)
|
||||
[](https://www.paypal.me/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)
|
||||
@@ -24,31 +22,26 @@ API than you are likely to write from scratch.
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://gnuhost.eu/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="static/gnuhost.png">
|
||||
<a href="https://supabase.io?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage" target="_blank">
|
||||
<img width="296px" src="static/supabase.svg">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="static/neon.jpg">
|
||||
<a href="https://www.euronodes.com/postgrest" target="_blank">
|
||||
<img width="296px" src="static/euronodes.svg">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="static/code-build.png">
|
||||
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="static/neon.jpg">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://supabase.io?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage" target="_blank">
|
||||
<img width="296px" src="static/supabase.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="static/tembo.png">
|
||||
<a href="https://www.bytebase.com/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="static/bytebase.svg">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -59,8 +52,8 @@ Big thanks to our sponsors! You can join them by supporting PostgREST on [Patreo
|
||||
|
||||
## Usage
|
||||
|
||||
1. Download the binary ([latest release](https://github.com/PostgREST/postgrest/releases/latest))
|
||||
for your platform.
|
||||
1. See the docs for [how to install PostgREST on your platform](https://docs.postgrest.org/en/stable/explanations/install.html). You can also [use Docker](https://docs.postgrest.org/en/stable/explanations/install.html#docker).
|
||||
|
||||
2. Invoke for help:
|
||||
|
||||
```bash
|
||||
@@ -145,14 +138,14 @@ and the [API guide](http://postgrest.org/en/stable/api.html).
|
||||
|
||||
## Supporting development
|
||||
|
||||
You can help PostgREST ongoing maintenance and development by:
|
||||
|
||||
- Making a regular donation through Patreon https://www.patreon.com/postgrest
|
||||
|
||||
- Alternatively, you can make a one-time donation via Paypal https://www.paypal.me/postgrest
|
||||
You can help PostgREST ongoing maintenance and development by making a regular donation through Patreon https://www.patreon.com/postgrest
|
||||
|
||||
Every donation will be spent on making PostgREST better for the whole community.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are always welcome and appreciated. Please see the [Contributing guidelines](https://github.com/PostgREST/postgrest/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## Thanks
|
||||
|
||||
The PostgREST organization is grateful to:
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
packages: postgrest.cabal
|
||||
tests: true
|
||||
package *
|
||||
ghc-options: -split-sections
|
||||
|
||||
@@ -1 +1 @@
|
||||
index-state: hackage.haskell.org 2024-05-17T23:41:49Z
|
||||
index-state: hackage.haskell.org 2025-10-29T04:02:18Z
|
||||
|
||||
@@ -3,7 +3,15 @@
|
||||
, compiler ? "ghc948"
|
||||
|
||||
, # Commit of the Nixpkgs repository that we want to use.
|
||||
nixpkgsVersion ? import nix/nixpkgs-version.nix
|
||||
# It defaults to reading the inputs from flake.lock, which serves
|
||||
# as a compatibility layer for non-flake builds / default.nix / shell.nix.
|
||||
nixpkgsVersion ? let
|
||||
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
|
||||
in
|
||||
{
|
||||
inherit (lock.nodes.nixpkgs.locked) owner repo rev;
|
||||
tarballHash = lock.nodes.nixpkgs.locked.narHash;
|
||||
}
|
||||
|
||||
, # Nix files that describe the Nixpkgs repository. We evaluate the expression
|
||||
# using `import` below.
|
||||
@@ -19,7 +27,7 @@ let
|
||||
"postgrest";
|
||||
|
||||
# PostgREST source files, filtered based on the rules in the .gitignore files
|
||||
# and file extensions. We want to include as litte as possible, as the files
|
||||
# and file extensions. We want to include as little as possible, as the files
|
||||
# added here will increase the space used in the Nix store and trigger the
|
||||
# build of new Nix derivations when changed.
|
||||
src =
|
||||
@@ -35,10 +43,6 @@ let
|
||||
allOverlays.build-toolbox
|
||||
allOverlays.checked-shell-script
|
||||
allOverlays.gitignore
|
||||
allOverlays.postgresql-libpq
|
||||
allOverlays.postgresql-legacy
|
||||
allOverlays.postgresql-future
|
||||
allOverlays.postgis
|
||||
(allOverlays.haskell-packages { inherit compiler; })
|
||||
allOverlays.slocat
|
||||
];
|
||||
@@ -49,19 +53,23 @@ let
|
||||
|
||||
postgresqlVersions =
|
||||
[
|
||||
{ name = "postgresql-16"; postgresql = pkgs.postgresql_16.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "postgresql-15"; postgresql = pkgs.postgresql_15.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "postgresql-14"; postgresql = pkgs.postgresql_14.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "postgresql-13"; postgresql = pkgs.postgresql_13.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "postgresql-12"; postgresql = pkgs.postgresql_12.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "postgresql-11"; postgresql = pkgs.postgresql_11.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "postgresql-10"; postgresql = pkgs.postgresql_10.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "postgresql-9_6"; postgresql = pkgs.postgresql_9_6.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "pg-17"; postgresql = pkgs.postgresql_17.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "pg-16"; postgresql = pkgs.postgresql_16.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "pg-15"; postgresql = pkgs.postgresql_15.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "pg-14"; postgresql = pkgs.postgresql_14.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "pg-13"; postgresql = pkgs.postgresql_13.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
];
|
||||
|
||||
haskellPackages = pkgs.haskell.packages."${compiler}";
|
||||
|
||||
# Dynamic derivation for PostgREST
|
||||
postgrest =
|
||||
pkgs.haskell.packages."${compiler}".callCabal2nix name src { };
|
||||
postgrest = pkgs.lib.pipe (haskellPackages.callCabal2nix name src { }) [
|
||||
# To allow ghc-datasize to be used.
|
||||
lib.disableLibraryProfiling
|
||||
# We are never going to use dynamic haskell libraries anyway. "Dynamic" refers to how
|
||||
# non-haskell deps are linked. All haskell dependencies are always statically linked.
|
||||
lib.disableSharedLibraries
|
||||
];
|
||||
|
||||
staticHaskellPackage = import nix/static.nix { inherit compiler name pkgs src; };
|
||||
|
||||
@@ -69,15 +77,6 @@ let
|
||||
devCabalOptions =
|
||||
"-f dev --test-show-detail=direct";
|
||||
|
||||
profiledHaskellPackages =
|
||||
pkgs.haskell.packages."${compiler}".extend (_: super:
|
||||
{
|
||||
mkDerivation =
|
||||
args:
|
||||
super.mkDerivation (args // { enableLibraryProfiling = true; });
|
||||
}
|
||||
);
|
||||
|
||||
inherit (pkgs.haskell) lib;
|
||||
in
|
||||
rec {
|
||||
@@ -85,17 +84,21 @@ rec {
|
||||
|
||||
# Derivation for the PostgREST Haskell package, including the executable,
|
||||
# libraries and documentation. We disable running the test suite on Nix
|
||||
# builds, as they require a database to be set up.
|
||||
postgrestPackage =
|
||||
lib.dontCheck postgrest;
|
||||
# builds, as they require a database to be set up. We split the binary
|
||||
# into a separate output, so that the default distribution via flake.nix
|
||||
# has a much smaller closure size.
|
||||
postgrestPackage = pkgs.lib.pipe postgrest [
|
||||
lib.dontCheck
|
||||
lib.enableSeparateBinOutput
|
||||
(haskellPackages.generateOptparseApplicativeCompletions [ "postgrest" ])
|
||||
];
|
||||
|
||||
# Profiled dynamic executable.
|
||||
postgrestProfiled =
|
||||
lib.enableExecutableProfiling (
|
||||
lib.dontHaddock (
|
||||
lib.dontCheck (profiledHaskellPackages.callCabal2nix name src { })
|
||||
)
|
||||
);
|
||||
postgrestProfiled = pkgs.lib.pipe postgrestPackage [
|
||||
lib.enableExecutableProfiling
|
||||
lib.enableLibraryProfiling
|
||||
lib.dontHaddock
|
||||
];
|
||||
|
||||
inherit (postgrest) env;
|
||||
|
||||
@@ -121,21 +124,21 @@ rec {
|
||||
docs =
|
||||
pkgs.callPackage nix/tools/docs.nix { };
|
||||
|
||||
# Git tools.
|
||||
gitTools =
|
||||
pkgs.callPackage nix/tools/gitTools.nix { };
|
||||
|
||||
# Load testing tools.
|
||||
loadtest =
|
||||
pkgs.callPackage nix/tools/loadtest.nix { inherit withTools; };
|
||||
|
||||
# Script for running memory tests.
|
||||
memory =
|
||||
pkgs.callPackage nix/tools/memory.nix { inherit postgrestProfiled withTools; };
|
||||
|
||||
# Utility for updating the pinned version of Nixpkgs.
|
||||
nixpkgsTools =
|
||||
pkgs.callPackage nix/tools/nixpkgsTools.nix { };
|
||||
|
||||
# Scripts for publishing new releases.
|
||||
release =
|
||||
pkgs.callPackage nix/tools/release { };
|
||||
pkgs.callPackage nix/tools/release.nix { };
|
||||
|
||||
# Linting and styling tools.
|
||||
style =
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# PostgREST
|
||||
|
||||
[](https://gitter.im/begriffs/postgrest)
|
||||
[](https://www.patreon.com/postgrest)
|
||||
[](https://www.paypal.me/postgrest)
|
||||
[](http://postgrest.org)
|
||||
[](https://github.com/PostgREST/postgrest/actions?query=branch%3Amain)
|
||||
|
||||
@@ -21,31 +19,26 @@ write from scratch.
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://gnuhost.eu/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/gnuhost.png">
|
||||
<a href="https://supabase.io?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage" target="_blank">
|
||||
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/supabase.svg">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/neon.jpg">
|
||||
<a href="https://www.euronodes.com/postgrest" target="_blank">
|
||||
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/euronodes.svg">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/code-build.png">
|
||||
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/neon.jpg">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://supabase.io?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage" target="_blank">
|
||||
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/supabase.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/tembo.png">
|
||||
<a href="https://www.bytebase.com/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
|
||||
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/bytebase.svg">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -66,7 +59,7 @@ The image is built from scratch using
|
||||
[Nix](https://nixos.org/nixpkgs/manual/#sec-pkgs-dockerTools) instead of a
|
||||
`Dockerfile`, which yields a highly secure and optimized image. This is also why
|
||||
no commands are listed in the image history. See the [PostgREST
|
||||
respository](https://github.com/PostgREST/postgrest/tree/main/nix/tools/docker) for
|
||||
repository](https://github.com/PostgREST/postgrest/tree/main/nix/tools/docker) for
|
||||
details on the build process and how to inspect the image.
|
||||
|
||||
This does not apply to the arm64 variant, which is based on Ubuntu.
|
||||
|
||||
@@ -5,35 +5,20 @@ The ER diagrams were created with https://github.com/BurntSushi/erd/.
|
||||
You can go download erd from https://github.com/BurntSushi/erd/releases and then do:
|
||||
|
||||
```bash
|
||||
./erd_static-x86-64 -i film.er -o ../_static/film.png
|
||||
./erd_static-x86-64 -i ./er/film.er -o ../_static/film.png
|
||||
```
|
||||
|
||||
The fonts used belong to the GNU FreeFont family. You can download them here: http://ftp.gnu.org/gnu/freefont/
|
||||
|
||||
## LaTeX
|
||||
## UML
|
||||
|
||||
The schema structure diagram is done with LaTeX. You can use a GUI like https://www.mathcha.io/editor to create the .tex file.
|
||||
The UML diagrams are created with https://plantuml.com/.
|
||||
|
||||
Then use this command to generate the png file.
|
||||
PlantUML only creates one diagram per file.
|
||||
That's why we need to create another one for dark mode.
|
||||
For example, for the file [uml/arch.uml](uml/arch.uml) there's [uml/dark/arch-dark.uml](uml/dark/arch-dark.uml) which includes the first one:
|
||||
|
||||
```bash
|
||||
postgrest-docs-render
|
||||
```
|
||||
|
||||
LaTeX is used because it's a tweakable plain text format.
|
||||
|
||||
You can install the full latex suite with `nix`:
|
||||
|
||||
```
|
||||
nix-env -iA texlive.combined.scheme-full
|
||||
```
|
||||
|
||||
To tweak the file with a live reload environment use:
|
||||
|
||||
```bash
|
||||
# open the pdf(zathura used as an example)
|
||||
zathura db.pdf &
|
||||
|
||||
# live reload with entr
|
||||
echo db.tex | entr pdflatex --shell-escape -halt-on-error db.tex
|
||||
plantuml -tsvg uml/arch.uml -o ../../_static
|
||||
plantuml -tsvg -darkmode uml/dark/arch-dark.uml -o ../../../_static
|
||||
```
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
@startuml
|
||||
|
||||
package "PostgREST" {
|
||||
() HTTP as HTTPAPI
|
||||
HTTPAPI - [Auth]
|
||||
[Auth] -r.> [ApiRequest]
|
||||
[ApiRequest] -r.> [Plan]
|
||||
[Plan] -r.> [Query]
|
||||
[Query] - () "Connection Pool" : "\t"
|
||||
[Plan] -u-> [Schema Cache]:uses
|
||||
[Schema Cache] <- () Listener : reloads
|
||||
|
||||
() HTTP as HTTPADMIN
|
||||
[Admin] -r- () HTTPADMIN
|
||||
[Config] -l- () CLI
|
||||
|
||||
[Config] <-l~ Listener
|
||||
|
||||
HTTPADMIN -[hidden]r- CLI
|
||||
Listener -[hidden]r- [Schema Cache]
|
||||
Listener -[hidden]r- [Config]
|
||||
[Schema Cache] -l[hidden]- [Config]
|
||||
[Schema Cache] -l[hidden]- [Admin]
|
||||
[Schema Cache] -l[hidden]- CLI
|
||||
}
|
||||
|
||||
|
||||
database "PostgreSQL" {
|
||||
node "API schema" as API {
|
||||
rectangle "Functions, Views"
|
||||
}
|
||||
node Authorization {
|
||||
rectangle "Roles, GRANT, RLS"
|
||||
}
|
||||
rectangle "Tables, extensions" as tbs
|
||||
API -d- tbs
|
||||
|
||||
API -[hidden]l- Authorization
|
||||
}
|
||||
|
||||
:user:
|
||||
hexagon Proxy
|
||||
:user: .r-> Proxy
|
||||
HTTPAPI <.l- Proxy
|
||||
|
||||
:operator: .d-> HTTPADMIN
|
||||
:operator: .d-> CLI
|
||||
|
||||
|
||||
PostgreSQL <.developer : "\t"
|
||||
Listener -r.> "PostgreSQL"
|
||||
"Connection Pool" -r.> "PostgreSQL" : "\t\t"
|
||||
|
||||
|
||||
note bottom of Auth
|
||||
Authenticates the user request
|
||||
end note
|
||||
|
||||
note bottom of ApiRequest
|
||||
Parses the URL syntax
|
||||
end note
|
||||
|
||||
note bottom of Query
|
||||
Generates the SQL
|
||||
end note
|
||||
|
||||
note top of Listener
|
||||
LISTEN session
|
||||
end note
|
||||
@enduml
|
||||
@@ -1,71 +0,0 @@
|
||||
\documentclass[convert]{standalone}
|
||||
\usepackage{amsmath}
|
||||
\usepackage{tikz}
|
||||
\usepackage{mathdots}
|
||||
\usepackage{yhmath}
|
||||
\usepackage{cancel}
|
||||
\usepackage{color}
|
||||
\usepackage{siunitx}
|
||||
\usepackage{array}
|
||||
\usepackage{multirow}
|
||||
\usepackage{amssymb}
|
||||
\usepackage{gensymb}
|
||||
\usepackage{tabularx}
|
||||
\usepackage{booktabs}
|
||||
\usetikzlibrary{fadings}
|
||||
\usetikzlibrary{patterns}
|
||||
\usetikzlibrary{shadows.blur}
|
||||
\usetikzlibrary{shapes}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\newcommand\customScale{0.35}
|
||||
|
||||
\begin{tikzpicture}[x=0.75pt,y=0.75pt,yscale=-1,xscale=1, scale=\customScale, every node/.style={scale=\customScale}]
|
||||
|
||||
%Shape: Can [id:dp7234864758664346]
|
||||
\draw [fill={rgb, 255:red, 47; green, 97; blue, 144 } ,fill opacity=1 ] (497.5,51.5) -- (497.5,255.5) .. controls (497.5,275.66) and (423.18,292) .. (331.5,292) .. controls (239.82,292) and (165.5,275.66) .. (165.5,255.5) -- (165.5,51.5) .. controls (165.5,31.34) and (239.82,15) .. (331.5,15) .. controls (423.18,15) and (497.5,31.34) .. (497.5,51.5) .. controls (497.5,71.66) and (423.18,88) .. (331.5,88) .. controls (239.82,88) and (165.5,71.66) .. (165.5,51.5) ;
|
||||
%Shape: Rectangle [id:dp7384065579958246]
|
||||
\draw [fill={rgb, 255:red, 236; green, 227; blue, 227 } ,fill opacity=1 ] (189,115) -- (252.5,115) -- (252.5,155) -- (189,155) -- cycle ;
|
||||
%Shape: Rectangle [id:dp24763906430298177]
|
||||
\draw [fill={rgb, 255:red, 236; green, 227; blue, 227 } ,fill opacity=1 ] (292,118) -- (362,118) -- (362,158) -- (292,158) -- cycle ;
|
||||
%Shape: Rectangle [id:dp3775601612537265]
|
||||
\draw [fill={rgb, 255:red, 236; green, 227; blue, 227 } ,fill opacity=1 ] (397,114) -- (467,114) -- (467,154) -- (397,154) -- cycle ;
|
||||
%Shape: Rectangle [id:dp7071457022893852]
|
||||
\draw [fill={rgb, 255:red, 248; green, 231; blue, 28 } ,fill opacity=1 ] (269,199) -- (397.5,199) -- (397.5,273) -- (269,273) -- cycle ;
|
||||
%Straight Lines [id:da8846759047437789]
|
||||
\draw (268,234) -- (226.44,155.77) ;
|
||||
\draw [shift={(225.5,154)}, rotate = 422.02] [color={rgb, 255:red, 0; green, 0; blue, 0 } ][line width=0.75] (10.93,-3.29) .. controls (6.95,-1.4) and (3.31,-0.3) .. (0,0) .. controls (3.31,0.3) and (6.95,1.4) .. (10.93,3.29) ;
|
||||
%Straight Lines [id:da6908444738113828]
|
||||
\draw (309.5,198) -- (307.6,161) ;
|
||||
\draw [shift={(307.5,159)}, rotate = 447.06] [color={rgb, 255:red, 0; green, 0; blue, 0 } ][line width=0.75] (10.93,-3.29) .. controls (6.95,-1.4) and (3.31,-0.3) .. (0,0) .. controls (3.31,0.3) and (6.95,1.4) .. (10.93,3.29) ;
|
||||
%Straight Lines [id:da7168757864413169]
|
||||
\draw (398.5,233) -- (431.72,154.84) ;
|
||||
\draw [shift={(432.5,153)}, rotate = 473.03] [color={rgb, 255:red, 0; green, 0; blue, 0 } ][line width=0.75] (10.93,-3.29) .. controls (6.95,-1.4) and (3.31,-0.3) .. (0,0) .. controls (3.31,0.3) and (6.95,1.4) .. (10.93,3.29) ;
|
||||
%Up Down Arrow [id:dp14059754167108496]
|
||||
\draw [fill={rgb, 255:red, 126; green, 211; blue, 33 } ,fill opacity=1 ] (312.5,288.5) -- (330,273) -- (347.5,288.5) -- (338.75,288.5) -- (338.75,319.5) -- (347.5,319.5) -- (330,335) -- (312.5,319.5) -- (321.25,319.5) -- (321.25,288.5) -- cycle ;
|
||||
|
||||
% Text Node
|
||||
\draw (201,129) node [anchor=north west][inner sep=0.75pt] [align=left] {tables};
|
||||
% Text Node
|
||||
\draw (307,130) node [anchor=north west][inner sep=0.75pt] [align=left ] {tables};
|
||||
% Text Node
|
||||
\draw (414,127) node [anchor=north west][inner sep=0.75pt] [align=left] {tables};
|
||||
% Text Node
|
||||
\draw (300,203) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 0; green, 0; blue, 0 } ,opacity=1 ] [align=center] { \\ views \\ + \\ \ \ functions};
|
||||
|
||||
% Text Node
|
||||
\draw (322,178) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 255; green, 255; blue, 255 } ,opacity=1 ] [align=left] {\large\textbf{api}};
|
||||
% Text Node
|
||||
\draw (190,97) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 255; green, 255; blue, 255 } ,opacity=1 ] [align=left] {\large\textbf{internal}};
|
||||
% Text Node
|
||||
\draw (300,99) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 255; green, 255; blue, 255 } ,opacity=1 ] [align=left] {\large\textbf{private}};
|
||||
% Text Node
|
||||
\draw (417,101) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 255; green, 255; blue, 255 } ,opacity=1 ] [align=left] {\large\textbf{core}};
|
||||
% Text Node
|
||||
\draw (358,306) node [anchor=north west][inner sep=0.75pt] [align=left] {REST};
|
||||
|
||||
\end{tikzpicture}
|
||||
|
||||
|
||||
\end{document}
|
||||
@@ -0,0 +1,96 @@
|
||||
@startuml
|
||||
|
||||
skinparam backgroundColor transparent
|
||||
|
||||
package "PostgREST" {
|
||||
() HTTP as HTTPAPI
|
||||
HTTPAPI - [Auth]
|
||||
[Auth] -r.> [ApiRequest]
|
||||
[ApiRequest] -r.> [Plan]
|
||||
[Plan] -r.> [Query]
|
||||
[Query] - () "Connection Pool" : "\t"
|
||||
[Plan] -u-> [Schema Cache]:uses
|
||||
[Schema Cache] <- () Listener : reloads
|
||||
|
||||
() HTTP as HTTPADMIN
|
||||
[Admin] -r- () HTTPADMIN
|
||||
[Config] -l- () CLI
|
||||
|
||||
[Config] <-r~ Listener
|
||||
|
||||
HTTPADMIN -[hidden]r- CLI
|
||||
[Schema Cache] -l[hidden]- [Config]
|
||||
[Schema Cache] -l[hidden]- [Admin]
|
||||
[Schema Cache] -l[hidden]- CLI
|
||||
}
|
||||
|
||||
|
||||
database "PostgreSQL" {
|
||||
node Authorization {
|
||||
rectangle "Roles, GRANT, RLS"
|
||||
}
|
||||
node "API schema" as API {
|
||||
rectangle "Functions, Views"
|
||||
}
|
||||
rectangle "Tables, extensions" as tbs
|
||||
API -d- tbs
|
||||
|
||||
API -l[hidden]- Authorization
|
||||
}
|
||||
|
||||
:user:
|
||||
hexagon Proxy
|
||||
:user: .r-> Proxy : request with JWT
|
||||
HTTPAPI <.l- Proxy
|
||||
|
||||
hexagon ExternalAuth
|
||||
ExternalAuth -u[hidden]- Proxy
|
||||
:user: .r-> ExternalAuth : login
|
||||
:user: <.r- ExternalAuth : JWT
|
||||
|
||||
:operator: .d-> HTTPADMIN
|
||||
:operator: .d-> CLI
|
||||
|
||||
|
||||
PostgreSQL <.developer : "\t"
|
||||
Listener -r.> "PostgreSQL"
|
||||
"Connection Pool" -r.> "PostgreSQL" : "\t\t"
|
||||
|
||||
note bottom of Auth
|
||||
Validates the JWT
|
||||
end note
|
||||
|
||||
note bottom of ApiRequest
|
||||
Parses the URL syntax
|
||||
end note
|
||||
|
||||
note bottom of Plan
|
||||
Generates internal AST
|
||||
end note
|
||||
|
||||
note bottom of Query
|
||||
Generates the SQL
|
||||
end note
|
||||
|
||||
note top of Listener
|
||||
LISTEN session
|
||||
end note
|
||||
|
||||
url of ExternalAuth is [[../explanations/external_auth.html]]
|
||||
url of Admin is [[../references/admin_server.html#admin-server]]
|
||||
url of API is [[../explanations/schema_isolation.html]]
|
||||
url of Auth is [[../references/auth.html#authn]]
|
||||
url of ApiRequest is [[../explanations/architecture.html#api-request]]
|
||||
url of Plan is [[../explanations/architecture.html#plan]]
|
||||
url of Query is [[../explanations/architecture.html#query]]
|
||||
url of Authorization is [[../explanations/db_authz.html]]
|
||||
url of CLI is [[../references/cli.html#cli]]
|
||||
url of "Connection Pool" is [[../references/connection_pool.html]]
|
||||
url of Config is [[../references/configuration.html#configuration]]
|
||||
url of HTTPADMIN is [[../explanations/architecture.html#http]]
|
||||
url of HTTPAPI is [[../explanations/architecture.html#http]]
|
||||
url of Listener is [[../references/listener.html#listener]]
|
||||
url of Proxy is [[../explanations/nginx.html]]
|
||||
url of "Schema Cache" is [[../references/schema_cache.html#schema-cache]]
|
||||
|
||||
@enduml
|
||||
@@ -0,0 +1,3 @@
|
||||
@startuml
|
||||
!include ../arch.uml
|
||||
@enduml
|
||||
@@ -0,0 +1,3 @@
|
||||
@startuml
|
||||
!include ../sch-iso.uml
|
||||
@enduml
|
||||
@@ -0,0 +1,29 @@
|
||||
@startuml
|
||||
|
||||
skinparam backgroundColor transparent
|
||||
skinparam linetype ortho
|
||||
|
||||
skinparam node {
|
||||
backgroundColor transparent
|
||||
borderThickness 1
|
||||
}
|
||||
|
||||
database "PostgreSQL" {
|
||||
node public {
|
||||
rectangle tables_public as "tables"
|
||||
}
|
||||
|
||||
node extensions as "**extensions**" {
|
||||
}
|
||||
|
||||
node API as "<size:20>api" {
|
||||
rectangle vf_api as "views + functions"
|
||||
}
|
||||
|
||||
tables_public <-- vf_api
|
||||
extensions <-- vf_api
|
||||
}
|
||||
|
||||
vf_api <-[thickness=3]-> () PostgREST
|
||||
|
||||
@enduml
|
||||
|
After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 29 KiB |
@@ -149,3 +149,7 @@ html[data-theme="dark"] .img-translucent img {
|
||||
transition: background-color 0.3s;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.svg-container-md {
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 468 B After Width: | Height: | Size: 156 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="391px" preserveAspectRatio="none" style="width:328px;height:391px;" version="1.1" viewBox="0 0 328 391" width="328px" zoomAndPan="magnify"><defs/><g><!--cluster PostgreSQL--><g id="cluster_PostgreSQL"><path d="M6,16 C6,6 158.5,6 158.5,6 C158.5,6 311,6 311,16 L311,293.59 C311,303.59 158.5,303.59 158.5,303.59 C158.5,303.59 6,303.59 6,293.59 L6,16 " fill="none" style="stroke:#E7E7E7;stroke-width:1.0;"/><path d="M6,16 C6,26 158.5,26 158.5,26 C158.5,26 311,26 311,16 " fill="none" style="stroke:#E7E7E7;stroke-width:1.0;"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="92.2305" x="112.3848" y="40.9951">PostgreSQL</text></g><!--cluster public--><g id="cluster_public"><polygon fill="none" points="30,74,40,64,153,64,153,146.29,143,156.29,30,156.29,30,74" style="stroke:#E7E7E7;stroke-width:1.0;"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="143" x2="153" y1="74" y2="64"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="30" x2="143" y1="74" y2="74"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="143" x2="143" y1="74" y2="156.29"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="47.9063" x="63.5469" y="89.9951">public</text></g><!--cluster API--><g id="cluster_API"><polygon fill="none" points="70,190.29,80,180.29,246,180.29,246,269.59,236,279.59,70,279.59,70,190.29" style="stroke:#E7E7E7;stroke-width:1.0;"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="236" x2="246" y1="190.29" y2="180.29"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="70" x2="236" y1="190.29" y2="190.29"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="236" x2="236" y1="190.29" y2="279.59"/><text fill="#FFFFFF" font-family="sans-serif" font-size="20" font-weight="bold" lengthAdjust="spacing" textLength="34.668" x="136.666" y="211.8545">api</text></g><!--entity tables_public--><g id="elem_tables_public"><rect fill="#313139" height="36.2969" rx="2.5" ry="2.5" style="stroke:#E7E7E7;stroke-width:0.5;" width="62.752" x="71.62" y="104"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="42.752" x="81.62" y="126.9951">tables</text></g><!--entity extensions--><g id="elem_extensions"><polygon fill="none" points="169.14,109,179.14,99,294.8695,99,294.8695,135.2969,284.8695,145.2969,169.14,145.2969,169.14,109" style="stroke:#E7E7E7;stroke-width:1.0;"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="284.8695" x2="294.8695" y1="109" y2="99"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="169.14" x2="284.8695" y1="109" y2="109"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="284.8695" x2="284.8695" y1="109" y2="145.2969"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="85.7295" x="184.14" y="131.9951">extensions</text></g><!--entity vf_api--><g id="elem_vf_api"><rect fill="#313139" height="36.2969" rx="2.5" ry="2.5" style="stroke:#E7E7E7;stroke-width:0.5;" width="144.6465" x="85.68" y="227.29"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="124.6465" x="95.68" y="250.2851">views + functions</text></g><!--entity PostgREST--><g id="elem_PostgREST"><ellipse cx="158" cy="352.59" fill="#313139" rx="8" ry="8" style="stroke:#E7E7E7;stroke-width:0.5;"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="74.6895" x="120.6553" y="382.5851">PostgREST</text></g><!--reverse link tables_public to vf_api--><g id="link_tables_public_vf_api"><path d="M110.03,146.6 C110.03,169.85 110.03,203.55 110.03,226.86 " fill="none" id="tables_public-backto-vf_api" style="stroke:#E7E7E7;stroke-width:1.0;"/><polygon fill="#E7E7E7" points="110.03,140.6,106.03,149.6,110.03,145.6,114.03,149.6,110.03,140.6" style="stroke:#E7E7E7;stroke-width:1.0;"/></g><!--reverse link extensions to vf_api--><g id="link_extensions_vf_api"><path d="M199.73,151.63 C199.73,175.24 199.73,205.18 199.73,226.88 " fill="none" id="extensions-backto-vf_api" style="stroke:#E7E7E7;stroke-width:1.0;"/><polygon fill="#E7E7E7" points="199.73,145.63,195.73,154.63,199.73,150.63,203.73,154.63,199.73,145.63" style="stroke:#E7E7E7;stroke-width:1.0;"/></g><!--link vf_api to PostgREST--><g id="link_vf_api_PostgREST"><path d="M158,269.62 C158,292.9 158,320.34 158,337.81 " fill="none" id="vf_api-PostgREST" style="stroke:#E7E7E7;stroke-width:3.0;"/><polygon fill="#E7E7E7" points="158,263.62,154,272.62,158,268.62,162,272.62,158,263.62" style="stroke:#E7E7E7;stroke-width:3.0;"/><polygon fill="#E7E7E7" points="158,343.81,162,334.81,158,338.81,154,334.81,158,343.81" style="stroke:#E7E7E7;stroke-width:3.0;"/></g><!--SRC=[KypCIyufJKbLqDFJBqxEqCqipjShpSq10000]--></g></svg>
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
@@ -12,7 +12,6 @@
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
@@ -50,7 +49,7 @@ source_suffix = ".rst"
|
||||
master_doc = "index"
|
||||
|
||||
# This is overriden by readthedocs with the version tag anyway
|
||||
version = "devel"
|
||||
version = "14"
|
||||
# To avoid repetition in <title> we set this to an empty string.
|
||||
release = ""
|
||||
|
||||
@@ -114,7 +113,7 @@ html_theme = "sphinx_rtd_theme"
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
html_theme_options = {"display_version": False}
|
||||
html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
# html_theme_path = []
|
||||
@@ -292,15 +291,22 @@ def setup(app):
|
||||
app.add_css_file("css/custom.css")
|
||||
|
||||
|
||||
# taken from https://github.com/sphinx-doc/sphinx/blob/82dad44e5bd3776ecb6fd8ded656bc8151d0e63d/sphinx/util/requests.py#L42
|
||||
user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0"
|
||||
user_agent = (
|
||||
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0"
|
||||
)
|
||||
|
||||
# TODO: these pages are returning 403 right now. Verify if they can be fixed by addressing the issue:
|
||||
# https://github.com/PostgREST/postgrest/issues/3544
|
||||
linkcheck_ignore = [
|
||||
r"https://stackoverflow.com/",
|
||||
# 403 only in CI / GitHub Actions
|
||||
r"https://www.patreon.com/postgrest",
|
||||
r"https://blog.frankel.ch/poor-man-api",
|
||||
r"https://www.cybertec-postgresql.com/.*",
|
||||
# Odd SSL error
|
||||
r"https://www.dripdepot.com",
|
||||
r"https://www.euronodes.com",
|
||||
# New GitHub UI delays comment load, so anchor fails
|
||||
r"https://github.com/.*#issuecomment",
|
||||
# Random 500 Internal Server Error
|
||||
r"https://jwt.io",
|
||||
]
|
||||
|
||||
# sphinx-tabs configuration
|
||||
|
||||
@@ -6,10 +6,7 @@ Community Tutorials
|
||||
* `Building a Contacts List with PostgREST and Vue.js <https://www.youtube.com/watch?v=iHtsALtD5-U>`_ -
|
||||
In this video series, DigitalOcean shows how to build and deploy an Nginx + PostgREST(using a managed PostgreSQL database) + Vue.js webapp in an Ubuntu server droplet.
|
||||
|
||||
* `PostgREST + Auth0: Create REST API in mintutes, and add social login using Auth0 <https://samkhawase.com/blog/postgrest/>`_ - A step-by-step tutorial to show how to dockerize and integrate Auth0 to PostgREST service.
|
||||
|
||||
* `PostgREST + PostGIS API tutorial in 5 minutes <https://gis-ops.com/postgrest-postgis-api-tutorial-geospatial-api-in-5-minutes/>`_ -
|
||||
In this tutorial, GIS • OPS shows how to perform PostGIS calculations through PostgREST :ref:`functions` interface.
|
||||
* `PostgREST + Auth0: Create REST API in minutes, and add social login using Auth0 <https://samkhawase.com/blog/postgrest-1-introduction/>`_ - A step-by-step tutorial to show how to dockerize and integrate Auth0 to PostgREST service.
|
||||
|
||||
* `"CodeLess" backend using postgres, postgrest and oauth2 authentication with keycloak <https://www.mathieupassenaud.fr/codeless_backend/>`_ -
|
||||
A step-by-step tutorial for using PostgREST with KeyCloak(hosted on a managed service).
|
||||
@@ -37,6 +34,7 @@ Templates
|
||||
Example Apps
|
||||
------------
|
||||
|
||||
* `archtika <https://github.com/thiloho/archtika>`_ - self-hosted CMS
|
||||
* `delibrium-postgrest <https://gitlab.com/delibrium/delibrium-postgrest/>`_ - example school API and front-end in Vue.js
|
||||
* `ETH-transactions-storage <https://github.com/Adamant-im/ETH-transactions-storage>`_ - indexer for Ethereum to get transaction list by ETH address
|
||||
* `general <https://github.com/PierreRochard/general>`_ - example auth back-end
|
||||
@@ -62,6 +60,7 @@ External Notification
|
||||
|
||||
These are PostgreSQL bridges that propagate LISTEN/NOTIFY to external queues for further processing. This allows functions to initiate actions outside the database such as sending emails.
|
||||
|
||||
* `pg-notify-stdout <https://github.com/mkleczek/pg-notify-stdout>`_ - writes notifications to standard output (use in shell scripts etc.)
|
||||
* `pg-notify-webhook <https://github.com/vbalasu/pg-notify-webhook>`_ - trigger webhooks from PostgreSQL's LISTEN/NOTIFY
|
||||
* `pgsql-listen-exchange <https://github.com/gmr/pgsql-listen-exchange>`_ - RabbitMQ
|
||||
* `postgres-websockets <https://github.com/diogob/postgres-websockets>`_ - expose web sockets for PostgreSQL's LISTEN/NOTIFY
|
||||
@@ -89,7 +88,7 @@ Client-Side Libraries
|
||||
* `postgrest-go <https://github.com/supabase-community/postgrest-go>`_ - Go
|
||||
* `postgrest-js <https://github.com/supabase/postgrest-js>`_ - TypeScript/JavaScript
|
||||
* `postgrest-kt <https://github.com/supabase-community/postgrest-kt>`_ - Kotlin
|
||||
* `postgrest-py <https://github.com/supabase-community/postgrest-py>`_ - Python
|
||||
* `postgrest-py <https://github.com/supabase/postgrest-py>`_ - Python
|
||||
* `postgrest-rs <https://github.com/supabase-community/postgrest-rs>`_ - Rust
|
||||
* `postgrest-swift <https://github.com/supabase-community/postgrest-swift>`_ - Swift
|
||||
* `redux-postgrest <https://github.com/andytango/redux-postgrest>`_ - TypeScript/JS, client integrated with (React) Redux.
|
||||
|
||||
@@ -6,7 +6,22 @@ This page describes the architecture of PostgREST.
|
||||
Bird's Eye View
|
||||
===============
|
||||
|
||||
.. image:: ../_static/arch.png
|
||||
You can click on the components to navigate to their respective documentation.
|
||||
|
||||
.. container:: img-dark
|
||||
|
||||
.. See https://github.com/sphinx-doc/sphinx/issues/2240#issuecomment-187366626
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<object width="100%" data="../_static/arch-dark.svg" type="image/svg+xml"></object>
|
||||
|
||||
.. container:: img-light
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<object width="100%" data="../_static/arch.svg" type="image/svg+xml"></object>
|
||||
|
||||
|
||||
Code Map
|
||||
========
|
||||
@@ -43,7 +58,7 @@ A request might be rejected at this level if it's invalid. For example when prov
|
||||
Plan
|
||||
----
|
||||
|
||||
Using the Schema Cache, `Plan.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/Plan.hs>`_ fills in out-of-band SQL details (like an ``ON CONFLICT (pk)`` clause) required to complete the user request.
|
||||
Using the Schema Cache, `Plan.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/Plan.hs>`_ generates an internal AST, filling out-of-band SQL details (like an ``ON CONFLICT (pk)`` clause) required to complete the user request.
|
||||
|
||||
A request might be rejected at this level if it's invalid. For example when doing resource embedding on a nonexistent resource.
|
||||
|
||||
@@ -77,5 +92,4 @@ The HTTP server is provided by `Warp <https://aosabook.org/en/posa/warp.html>`_.
|
||||
Listener
|
||||
--------
|
||||
|
||||
`Listener.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/Listener.hs>`_ is in charge of maintaining a `LISTEN session <https://www.postgresql.org/docs/current/sql-listen.html>`_
|
||||
that keeps the :ref:`schema_cache` and the :ref:`in_db_config` up to date.
|
||||
`Listener.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/Listener.hs>`_ is in charge of the :ref:`listener`.
|
||||
|
||||
@@ -13,9 +13,9 @@ A role can be thought of as either a database user, or a group of database users
|
||||
Roles for Each Web User
|
||||
-----------------------
|
||||
|
||||
PostgREST can accommodate either viewpoint. If you treat a role as a single user then the :ref:`jwt_impersonation` does most of what you need. When an authenticated user makes a request PostgREST will switch into the database role for that user, which in addition to restricting queries, is available to SQL through the :code:`current_user` variable.
|
||||
PostgREST can accommodate either viewpoint. If you treat a role as a single user then :ref:`user_impersonation` does most of what you need. When an authenticated user makes a request PostgREST will switch into the database role for that user, which in addition to restricting queries, is available to SQL through the :code:`current_user` variable.
|
||||
|
||||
You can use row-level security to flexibly restrict visibility and access for the current user. Here is an `example <https://www.2ndquadrant.com/en/blog/application-users-vs-row-level-security/>`_ from Tomas Vondra, a chat table storing messages sent between users. Users can insert rows into it to send messages to other users, and query it to see messages sent to them by other users.
|
||||
You can use row-level security to flexibly restrict visibility and access for the current user. Here is an `example <https://www.enterprisedb.com:443/blog/application-users-vs-row-level-security>`_ from Tomas Vondra, a chat table storing messages sent between users. Users can insert rows into it to send messages to other users, and query it to see messages sent to them by other users.
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.. _external_jwt:
|
||||
.. _external_auth:
|
||||
|
||||
External JWT Generation
|
||||
External Authentication
|
||||
-----------------------
|
||||
|
||||
JWT from Auth0
|
||||
@@ -3,7 +3,7 @@
|
||||
Installation
|
||||
############
|
||||
|
||||
The release page has `pre-compiled binaries for macOS, Windows, Linux and FreeBSD <https://github.com/PostgREST/postgrest/releases/latest>`_ .
|
||||
The release page has `pre-compiled binaries for macOS, Windows, Linux and FreeBSD <https://github.com/PostgREST/postgrest/releases/latest>`_.
|
||||
The Linux binary is a static executable that can be run on any Linux distribution.
|
||||
|
||||
You can also use your OS package manager.
|
||||
@@ -16,16 +16,11 @@ Supported PostgreSQL versions
|
||||
=============================
|
||||
|
||||
=============== =================================
|
||||
**Supported** PostgreSQL >= 9.6
|
||||
**Supported** PostgreSQL >= 13
|
||||
=============== =================================
|
||||
|
||||
PostgREST works with all PostgreSQL versions starting from 9.6.
|
||||
PostgREST works with all PostgreSQL versions still `officially supported <https://www.postgresql.org/support/versioning/>`_.
|
||||
|
||||
.. note::
|
||||
|
||||
Support for PostgreSQL versions 9.6, 10 and 11 is deprecated. From this on version onwards, PostgREST will only support non-end-of-life PostgreSQL versions.
|
||||
|
||||
See https://www.postgresql.org/support/versioning/.
|
||||
|
||||
Running PostgREST
|
||||
=================
|
||||
@@ -80,8 +75,12 @@ You can get the `official PostgREST Docker image <https://hub.docker.com/r/postg
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# pull the latest version
|
||||
docker pull postgrest/postgrest
|
||||
|
||||
# to pull a particular version, use one of the versions on https://hub.docker.com/r/postgrest/postgrest/tags
|
||||
docker pull postgrest/postgrest:<version>
|
||||
|
||||
To configure the container image, use :ref:`env_variables_config`.
|
||||
|
||||
There are two ways to run the PostgREST container: with an existing external database, or through docker-compose.
|
||||
@@ -147,6 +146,7 @@ To avoid having to install the database at all, you can run both it and the serv
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
PGRST_SERVER_HOST: 0.0.0.0 # necessary for `postgrest --ready` flag to work
|
||||
PGRST_DB_URI: postgres://app_user:password@db:5432/app_db
|
||||
PGRST_OPENAPI_SERVER_PROXY_URI: http://127.0.0.1:3000
|
||||
depends_on:
|
||||
@@ -190,7 +190,7 @@ When a pre-built binary does not exist for your system you can build the project
|
||||
|
||||
You can build PostgREST from source with `Stack <https://github.com/commercialhaskell/stack>`_. It will install any necessary Haskell dependencies on your system.
|
||||
|
||||
* `Install Stack <https://docs.haskellstack.org/en/stable/README/#how-to-install-stack>`_ for your platform
|
||||
* `Install Stack <https://docs.haskellstack.org/en/stable/#how-to-install-stack>`_ for your platform
|
||||
* Install Library Dependencies
|
||||
|
||||
===================== =======================================
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
.. note::
|
||||
|
||||
This page is a work in progress.
|
||||
|
||||
.. _schema_isolation:
|
||||
|
||||
Schema Isolation
|
||||
@@ -12,6 +8,18 @@ A PostgREST instance exposes all the tables, views, and functions of a single `P
|
||||
It is recommended that you don't expose tables on your API schema. Instead expose views and functions which insulate the internal details from the outside world.
|
||||
This allows you to change the internals of your schema and maintain backwards compatibility. It also keeps your code easier to refactor, and provides a natural way to do API versioning.
|
||||
|
||||
.. container:: img-translucent
|
||||
.. container:: svg-container-md
|
||||
|
||||
.. image:: ../_static/db.png
|
||||
.. container:: img-dark
|
||||
|
||||
.. See https://github.com/sphinx-doc/sphinx/issues/2240#issuecomment-187366626
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<object width="100%" data="../_static/sch-iso-dark.svg" type="image/svg+xml"></object>
|
||||
|
||||
.. container:: img-light
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<object width="100%" data="../_static/sch-iso.svg" type="image/svg+xml"></object>
|
||||
|
||||
@@ -43,7 +43,7 @@ As in :ref:`sql_user_management`, we create the :code:`pgcrypto` and :code:`pgjw
|
||||
CREATE EXTENSION pgcrypto WITH SCHEMA ext_pgcrypto;
|
||||
|
||||
|
||||
Concerning the `pgjwt extension <https://github.com/michelp/pgjwt>`_, please cf. to :ref:`client_auth`.
|
||||
Concerning the `pgjwt extension <https://github.com/michelp/pgjwt>`_, please cf. to :ref:`jwt-from-sql`.
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
@@ -157,7 +157,7 @@ Here we use the username instead of the email address to identify a user.
|
||||
Logins
|
||||
~~~~~~
|
||||
|
||||
As described in :ref:`client_auth`, we'll create a JWT token inside our login function. Note that you'll need to adjust the secret key which is hard-coded in this example to a secure (at least thirty-two character) secret of your choosing.
|
||||
As described in :ref:`jwt-from-sql`, we'll create a JWT token inside our login function. Note that you'll need to adjust the secret key which is hard-coded in this example to a secure (at least thirty-two character) secret of your choosing.
|
||||
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
SQL User Management
|
||||
===================
|
||||
|
||||
As mentioned on :ref:`jwt_generation`, an external service can provide user management and coordinate with the PostgREST server using JWT. It’s also possible to support logins entirely through SQL. It’s a fair bit of work, so get ready.
|
||||
As mentioned on :ref:`jwt_generation`, an external service can provide user management and coordinate with the PostgREST server using JWT. It's also possible to support logins entirely through SQL. It's a fair bit of work, so get ready.
|
||||
|
||||
Storing Users and Passwords
|
||||
---------------------------
|
||||
@@ -110,6 +110,8 @@ Then, add ``db-anon-role`` to the configuration file to allow anonymous requests
|
||||
|
||||
db-anon-role = "anon"
|
||||
|
||||
.. _jwt-from-sql:
|
||||
|
||||
JWT from SQL
|
||||
~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -16,15 +16,9 @@ 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
|
||||
|
||||
.. image:: https://img.shields.io/badge/Donate-PayPal-green.svg
|
||||
:target: https://www.paypal.com/paypalme/postgrest
|
||||
|
||||
|
|
||||
|
||||
PostgREST is a standalone web server that turns your PostgreSQL database directly into a RESTful API. The structural constraints and permissions in the database determine the API endpoints and operations.
|
||||
@@ -44,49 +38,53 @@ Sponsors
|
||||
.. image:: ../static/cybertec.svg
|
||||
:target: https://www.cybertec-postgresql.com/en/?utm_source=postgrest.org&utm_medium=referral&utm_campaign=postgrest
|
||||
|
||||
.. image:: ../static/gnuhost.png
|
||||
:target: https://gnuhost.eu/?utm_source=sponsor&utm_campaign=postgrest
|
||||
|
||||
.. container:: img-dark
|
||||
|
||||
.. image:: ../static/neon-dark.jpg
|
||||
:target: https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest
|
||||
.. image:: ../static/supabase-dark.svg
|
||||
:target: https://supabase.com/?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage
|
||||
|
||||
.. container:: img-light
|
||||
|
||||
.. image:: ../static/neon.jpg
|
||||
:target: https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest
|
||||
.. image:: ../static/supabase.svg
|
||||
:target: https://supabase.com/?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage
|
||||
|
||||
.. container:: img-dark
|
||||
|
||||
.. image:: ../static/euronodes.svg
|
||||
:target: https://www.euronodes.com/postgrest
|
||||
|
||||
.. container:: img-light
|
||||
|
||||
.. image:: ../static/euronodes.svg
|
||||
:target: https://www.euronodes.com/postgrest
|
||||
|
||||
|
|
||||
|
||||
.. container:: img-dark
|
||||
|
||||
.. image:: ../static/code-build-dark.png
|
||||
:target: https://code.build/?utm_source=sponsor&utm_campaign=postgrest
|
||||
.. image:: ../static/neon-dark.jpg
|
||||
:target: https://neon.com/?utm_source=sponsor&utm_campaign=postgrest
|
||||
|
||||
.. container:: img-light
|
||||
|
||||
.. image:: ../static/code-build.png
|
||||
:target: https://code.build/?utm_source=sponsor&utm_campaign=postgrest
|
||||
.. image:: ../static/neon.jpg
|
||||
:target: https://neon.com/?utm_source=sponsor&utm_campaign=postgrest
|
||||
|
||||
.. container:: img-dark
|
||||
|
||||
.. image:: ../static/supabase-dark.png
|
||||
:target: https://supabase.com/?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage
|
||||
.. image:: ../static/bytebase-dark.svg
|
||||
:target: https://www.bytebase.com/?utm_source=sponsor&utm_campaign=postgrest
|
||||
|
||||
.. container:: img-light
|
||||
|
||||
.. image:: ../static/supabase.png
|
||||
:target: https://supabase.com/?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage
|
||||
|
||||
.. image:: ../static/tembo.png
|
||||
:target: https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest
|
||||
.. image:: ../static/bytebase.svg
|
||||
:target: https://www.bytebase.com/?utm_source=sponsor&utm_campaign=postgrest
|
||||
|
||||
.. The static/empty.png(created with `convert -size 320x95 xc:#fcfcfc empty.png`) is an ugly workaround
|
||||
to create space and center the logos. It's not easy to layout with restructuredText.
|
||||
|
||||
.. .. image:: _static/empty.png
|
||||
:target: #sponsors
|
||||
.. image:: _static/empty.png
|
||||
:target: #sponsors
|
||||
|
||||
|
|
||||
|
||||
@@ -113,12 +111,19 @@ 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
|
||||
-------------
|
||||
Releases
|
||||
--------
|
||||
|
||||
The release notes are published on `PostgREST's GitHub release page <https://github.com/PostgREST/postgrest/releases>`_.
|
||||
PostgREST follows ``MAJOR.PATCH`` two-part versioning:
|
||||
|
||||
- ``MAJOR``: feature release, may deprecate or remove things.
|
||||
- ``PATCH``: fix/security release only; no features, no behavior changes.
|
||||
|
||||
Starting from ``v14.0``, only even-numbered MAJOR versions will be released, reserving odd-numbered MAJOR versions for development.
|
||||
|
||||
All the releases are published on `PostgREST's GitHub release page <https://github.com/PostgREST/postgrest/releases>`_.
|
||||
|
||||
Tutorials
|
||||
---------
|
||||
@@ -215,22 +220,14 @@ In Production
|
||||
Here are some companies that use PostgREST in production.
|
||||
|
||||
* `Catarse <https://www.catarse.me>`_
|
||||
* `Datrium <https://www.datrium.com>`_
|
||||
* `Drip Depot <https://www.dripdepot.com>`_
|
||||
* `Image-charts <https://www.image-charts.com>`_
|
||||
* `Moat <https://www.oracle.com/advertising/measurement/>`_
|
||||
* `Netwo <https://www.netwo.io>`_
|
||||
* `Nimbus <https://www.nimbusfacility.com/sg/home>`_
|
||||
- See how Nimbus uses PostgREST in `Paul Copplestone's blog post <https://paul.copplest.one/blog/nimbus-tech-2019-04.html>`_.
|
||||
* `OpenBooking <https://openbooking.ch>`_
|
||||
* `Redsmin <https://www.redsmin.com>`_
|
||||
* `Sompani <https://www.sompani.com>`_
|
||||
* `Supabase <https://supabase.com>`_
|
||||
|
||||
.. Failing links
|
||||
* `eGull <http://www.egull.co>`_
|
||||
* `MotionDynamic - Fast highly dynamic video generation at scale <https://motiondynamic.tech>`_
|
||||
|
||||
Testimonials
|
||||
------------
|
||||
|
||||
@@ -274,4 +271,21 @@ Testimonials
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Please see the `Contributing guidelines <https://github.com/PostgREST/postgrest/blob/main/.github/CONTRIBUTING.md>`_ in the main PostgREST repository.
|
||||
Please see the `Contributing guidelines <https://github.com/PostgREST/postgrest/blob/main/CONTRIBUTING.md>`_ in the main PostgREST repository.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<script type="text/javascript">
|
||||
let hash = window.location.hash;
|
||||
|
||||
const redirects = {
|
||||
// Tables and Views
|
||||
'#release-notes': '#releases',
|
||||
};
|
||||
|
||||
let willRedirectTo = redirects[hash];
|
||||
|
||||
if (willRedirectTo) {
|
||||
window.location.href = willRedirectTo;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
Greenplum
|
||||
#########
|
||||
|
||||
`Greenplum <https://greenplum.org/>`_ has been reported to work by adding ``LOGIN`` to the :ref:`anonymous and user roles <roles>`.
|
||||
|
||||
For more details, see https://github.com/PostgREST/postgrest/issues/2021.
|
||||
@@ -3,6 +3,7 @@ api
|
||||
API's
|
||||
APIs
|
||||
APISIX
|
||||
AST
|
||||
aud
|
||||
Auth
|
||||
auth
|
||||
@@ -12,10 +13,10 @@ booleans
|
||||
BOM
|
||||
Bytea
|
||||
Cardano
|
||||
casted
|
||||
cd
|
||||
centric
|
||||
CLI
|
||||
CMS
|
||||
coercible
|
||||
conf
|
||||
Cloudflare
|
||||
@@ -27,10 +28,12 @@ CSV
|
||||
durations
|
||||
DDL
|
||||
DOM
|
||||
DSL
|
||||
DevOps
|
||||
dockerize
|
||||
enum
|
||||
Enums
|
||||
Entra
|
||||
eq
|
||||
ETH
|
||||
Ethereum
|
||||
@@ -43,7 +46,6 @@ Github
|
||||
Google
|
||||
grantor
|
||||
GraphQL
|
||||
Greenplum
|
||||
gte
|
||||
GUC
|
||||
Haskell
|
||||
@@ -68,9 +70,11 @@ isdistinct
|
||||
JS
|
||||
js
|
||||
JSON
|
||||
JSPath
|
||||
JWK
|
||||
JWT
|
||||
jwt
|
||||
Keycloak
|
||||
Kubernetes
|
||||
localhost
|
||||
login
|
||||
@@ -94,10 +98,11 @@ npm
|
||||
nxl
|
||||
nxr
|
||||
OAuth
|
||||
ORM
|
||||
Observability
|
||||
Okta
|
||||
OpenAPI
|
||||
openapi
|
||||
ORM
|
||||
ov
|
||||
parametrized
|
||||
passphrase
|
||||
@@ -146,8 +151,6 @@ SHA
|
||||
signup
|
||||
SIGUSR
|
||||
sl
|
||||
spreaded
|
||||
Spreaded
|
||||
SQL
|
||||
sql
|
||||
SQLSTATE
|
||||
@@ -171,6 +174,7 @@ unikernel
|
||||
unix
|
||||
updatable
|
||||
unfulfillable
|
||||
unselected
|
||||
Untyped
|
||||
UPSERT
|
||||
Upsert
|
||||
@@ -190,3 +194,5 @@ Websockets
|
||||
webuser
|
||||
wfts
|
||||
www
|
||||
debouncing
|
||||
deduplicates
|
||||
@@ -12,7 +12,7 @@ Health Check
|
||||
|
||||
You can enable a health check to verify if PostgREST is available for client requests. Also to check the status of its internal state.
|
||||
|
||||
Two endpoints ``live`` and ``ready`` will then be available.
|
||||
Two endpoints ``live`` and ``ready`` will then be available. Both these endpoints reply with a status code and empty response body.
|
||||
|
||||
.. important::
|
||||
|
||||
@@ -55,23 +55,6 @@ Metrics
|
||||
|
||||
Provides :ref:`metrics`.
|
||||
|
||||
Runtime Configuration
|
||||
=====================
|
||||
|
||||
Provides a ``config`` endpoint that returns the runtime :ref:`configuration`.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3001/config"
|
||||
|
||||
.. code-block::
|
||||
|
||||
db-aggregates-enabled = false
|
||||
db-anon-role = "web_anon"
|
||||
db-channel = "pgrst"
|
||||
db-channel-enabled = false
|
||||
...
|
||||
|
||||
Runtime Schema Cache
|
||||
====================
|
||||
|
||||
|
||||
@@ -3,20 +3,20 @@
|
||||
Aggregate Functions
|
||||
###################
|
||||
|
||||
Aggregate functions allow you to summarize data by performing calculations across groups of rows. For instance, if you have an ``orders`` table that has an ``amount`` column, you could use an aggregate function to get the sum of the ``amount`` column, either for all rows, or for each group of rows that share specific values, for instance all rows that share the same ``order_date``.
|
||||
PostgREST supports the following aggregate functions: ``avg()``, ``count()``, ``max()``, ``min()``, and ``sum()``.
|
||||
Please refer to the `section on aggregate functions in the PostgreSQL documentation <https://www.postgresql.org/docs/current/functions-aggregate.html>`_ for a detailed explanation of these functions.
|
||||
|
||||
.. note::
|
||||
Aggregate functions are *disabled* by default in PostgREST, as without appropriate safeguards, aggregate functions can create performance problems. See :ref:`db-aggregates-enabled` for further details.
|
||||
Aggregate functions are *disabled* by default in PostgREST, because they can create performance problems without appropriate safeguards.
|
||||
See :ref:`db-aggregates-enabled` for further details.
|
||||
|
||||
PostgREST supports the following aggregate functions: ``avg()``, ``count()``, ``max()``, ``min()``, and ``sum()``. Please refer to the `section on aggregate functions in the PostgreSQL documentation <https://www.postgresql.org/docs/current/functions-aggregate.html>`_ for a detailed explanation of these functions.
|
||||
|
||||
To use an aggregate function, you append the function to a value in the ``select`` parameter, like so:
|
||||
To use an aggregate function, append it to a column in the ``select`` parameter, like so:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/orders?select=amount.sum()"
|
||||
|
||||
With the above query, PostgREST will return a single row with a single column named ``sum`` that contains the sum of all the values in the ``amount`` column:
|
||||
This will return a ``sum`` of all the values of the ``amount`` column in a single row:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
@@ -26,15 +26,29 @@ With the above query, PostgREST will return a single row with a single column na
|
||||
}
|
||||
]
|
||||
|
||||
You can use multiple aggregate functions by just adding more columns with aggregate functions to the ``select`` parameter.
|
||||
You can ``select`` multiple aggregate functions at the same time (you may need to :ref:`rename them <renaming_columns>` to disambiguate).
|
||||
|
||||
To group by other columns, you simply add those columns to the ``select`` parameter. For instance:
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/orders?select=total_amount:amount.sum(),avg_amount:amount.avg(),total_quantity:quantity.sum()"
|
||||
|
||||
.. note::
|
||||
Aggregate functions work alongside other PostgREST features, like :ref:`h_filter`, :ref:`json_columns`, and :ref:`ordering`.
|
||||
However they are not compatible with :ref:`domain_reps` for the moment.
|
||||
Additionally, PostgreSQL's ``HAVING`` clause and ordering by aggregated columns are not yet supported.
|
||||
|
||||
Automatic ``GROUP BY``
|
||||
======================
|
||||
|
||||
In SQL, a ``GROUP BY`` clause is required to aggregate the selected columns.
|
||||
However, PostgREST handles grouping automatically if the columns are already present in the ``select`` parameter.
|
||||
For instance:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/orders?select=amount.sum(),amount.avg(),order_date"
|
||||
|
||||
This will return a row for each unique value in the ``order_date`` column, with the sum and average of the ``amount`` column for all rows that share the same ``order_date``:
|
||||
This will get the sum and average of the amounts grouped by each unique value in the ``order_date`` column:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
@@ -51,67 +65,55 @@ This will return a row for each unique value in the ``order_date`` column, with
|
||||
}
|
||||
]
|
||||
|
||||
.. note::
|
||||
Aggregate functions work alongside other PostgREST features, like :ref:`h_filter`, :ref:`json_columns`, and :ref:`ordering`. Please note at this time aggregate functions are not compatible with :ref:`domain_reps`. Additionally, PostgreSQL's ``HAVING`` clause and ordering by aggregated columns are not yet supported.
|
||||
|
||||
The Case of ``count()``
|
||||
===========================
|
||||
The ``count()`` Aggregate
|
||||
=========================
|
||||
|
||||
.. note::
|
||||
Before the addition of aggregate functions, it was possible to count by adding ``count`` (without parentheses) to the ``select`` parameter. While this is still supported, it may be deprecated in the future, and thus use of this legacy feature is **not recommended.** Please use ``count()`` (with parentheses) instead.
|
||||
Before the addition of aggregate functions, it was possible to count by adding ``count`` (without parentheses) to the ``select`` parameter.
|
||||
While this is still supported, it may be deprecated in the future, and thus use of this legacy feature is **not recommended**.
|
||||
Please use ``count()`` (with parentheses) instead.
|
||||
|
||||
|
||||
``count()`` is treated specially, as it can be used without an associated column. Take for example the following query:
|
||||
``count()`` is a special case because it can be used with or without an aggregated column. For example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/orders?select=count(),order_date"
|
||||
|
||||
This would return a row for each unique value in the ``order_date`` column, with the count of all rows that share the same ``order_date``:
|
||||
curl "http://localhost:3000/orders?select=count(),observation_count:observation.count(),order_date"
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
[
|
||||
{
|
||||
"count": 4,
|
||||
"observation_count": 2,
|
||||
"order_date": "2023-01-01"
|
||||
},
|
||||
{
|
||||
"count": 2,
|
||||
"observation_count": 1,
|
||||
"order_date": "2023-01-02"
|
||||
}
|
||||
]
|
||||
|
||||
When ``count()`` is used with an associated column, its behavior is slightly different: It will return the count of all values that are not ``NULL``. This is due to how PostgreSQL itself implements the ``count()`` function.
|
||||
|
||||
Renaming and Casting
|
||||
====================
|
||||
|
||||
Renaming Aggregates
|
||||
-------------------
|
||||
|
||||
Just like with other columns, you can rename aggregated columns too. See :ref:`renaming_columns` for details.
|
||||
|
||||
Renaming columns is especially helpful in the context of aggregate functions, as by default a column with an aggregate function applied will take on the name of the applied aggregate function. You may want to provide a more semantically meaningful name or prevent collisions when using multiple aggregate functions of the same type.
|
||||
Note that there is a difference between the result of ``count()`` and ``observation.count()``.
|
||||
The former counts the whole row, while the latter counts the non ``NULL`` values of the ``observation`` column (both grouped by ``order_date``).
|
||||
This is due to how PostgreSQL itself implements the ``count()`` function.
|
||||
|
||||
Casting Aggregates
|
||||
------------------
|
||||
==================
|
||||
|
||||
When applying an aggregate function to a column, you are able to cast both the value of the input to the aggregate function *and* the value of the output from the aggregate function. In both cases, the syntax works as described in :ref:`casting_columns`, with the only difference being the placement of the cast.
|
||||
It is :ref:`possible to cast <casting_columns>` the aggregated column or the aggregate itself, or both at the same time.
|
||||
|
||||
Casting the Value of the Input
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Casting the Aggregated Column
|
||||
-----------------------------
|
||||
|
||||
For instance, imagine that the ``orders`` table has a JSON column, ``order_details``, and this column contains a JSON object that has a key, ``tax_amount``. Let's say you want to get the sum of the tax amount for every order. You can use the ``->`` or ``->>`` operators to extract the value with this key (see :ref:`json_columns`), but these operators will return values of the types JSON and ``text`` respectively, and neither of these types can be used with ``sum()``.
|
||||
|
||||
Therefore, you will need to first cast the input value to a type that is compatible with ``sum()`` (e.g. ``numeric``). Casting the input value is done in exactly the same way as casting any other value:
|
||||
For example, let's say that ``orders`` has an ``order_details`` :ref:`JSON column <json_columns>` with a ``tax_amount`` key.
|
||||
We cannot sum ``tax_amount`` directly because using ``->`` or ``->>`` will return the data in ``json`` or ``text`` format.
|
||||
So we need to cast it to a compatible type (e.g. ``numeric``) right before the aggregate function:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/orders?select=order_details->tax_amount::numeric.sum()"
|
||||
|
||||
With this, you will receive the sum of the casted ``tax_amount`` value:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
[
|
||||
@@ -120,17 +122,15 @@ With this, you will receive the sum of the casted ``tax_amount`` value:
|
||||
}
|
||||
]
|
||||
|
||||
Casting the Value of the Output
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Casting the Aggregate
|
||||
---------------------
|
||||
|
||||
Now let's return to an example involving the ``amount`` column of the ``orders`` table. Imagine that we want to get the rounded average of the ``amount`` column. One way to do this is to use the ``avg()`` aggregate function and then to cast the output value of the function to ``int``. To cast the value of the output of the function, we simply place the cast *after* the aggregate function:
|
||||
For instance, if we wanted to round the average of the ``amount`` column, we could do so by casting ``avg()`` to an ``int``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/orders?select=amount.avg()::int"
|
||||
|
||||
You will then receive the rounded average as the result:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
[
|
||||
@@ -139,27 +139,22 @@ You will then receive the rounded average as the result:
|
||||
}
|
||||
]
|
||||
|
||||
Of course, you can use both input and output casts at the same time, if you so desire.
|
||||
Aggregates and Resource Embedding
|
||||
=================================
|
||||
|
||||
You can group an aggregate function by an :ref:`embedded resource <resource_embedding>` and also use the aggregates inside them.
|
||||
|
||||
Using Aggregate Functions with Resource Embedding
|
||||
=================================================
|
||||
Grouping by an Embedded Resource
|
||||
--------------------------------
|
||||
|
||||
Aggregate functions can be used in conjunction with :ref:`resource_embedding`. You can use embedded resources as grouping columns, use aggregate functions within the context of an embedded resource, or use columns from a spreaded resource as grouping columns or as inputs to aggregate functions.
|
||||
|
||||
Using Embedded Resources as Grouping Columns
|
||||
--------------------------------------------
|
||||
|
||||
Using an embedded resource as a grouping column allows you to use data from an association to group the results of an aggregation.
|
||||
|
||||
For example, imagine that the ``orders`` table from the examples above is related to a ``customers`` table. If you want to get the sum of the ``amount`` column grouped by the ``name`` column from the ``customers`` table, you can include the customer name, using the standard :ref:`resource_embedding` syntax, and perform a sum on the ``amount`` column.
|
||||
Similar to grouping by columns, aggregate functions can also be grouped by embedded resources.
|
||||
For example, let's say that the ``orders`` table is related to a ``customers`` table.
|
||||
To get the sum of the ``amount`` column grouped by the ``name`` column from the ``customers`` table, we would do the following:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/orders?select=amount.sum(),customers(name)"
|
||||
|
||||
You will then get the summed amount, along with the embedded customer resource:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
[
|
||||
@@ -177,15 +172,16 @@ You will then get the summed amount, along with the embedded customer resource:
|
||||
}
|
||||
]
|
||||
|
||||
.. note::
|
||||
The previous example uses a has-one association to demonstrate this functionality, but you may also use has-many associations as grouping columns, although there are few obvious use cases for this.
|
||||
The previous example uses a "to-one" relationship, but this can be done on "to-many" relationships as well (although there are few obvious use cases).
|
||||
|
||||
Using Aggregate Functions Within the Context of an Embedded Resource
|
||||
--------------------------------------------------------------------
|
||||
This also works in a similar way for :ref:`spread embedded resources <spread_embed>`.
|
||||
For example, ``select=amount.sum(),...customers(name)`` would sum the ``amount`` grouped by the ``name`` column.
|
||||
|
||||
When embedding a resource, you can apply aggregate functions to columns from the associated resource to perform aggregations within the context of an embedded resource.
|
||||
Using Aggregates Inside Embedded Resources
|
||||
------------------------------------------
|
||||
|
||||
Continuing with the example relationship between ``orders`` and ``customers`` from the previous section, imagine that you want to fetch the ``name``, ``city``, and ``state`` for each customer, along with the sum of amount of the customer's orders, grouped by the order date. This can be done in the following way:
|
||||
Using the relationship from the previous example, let's take all the ``customers`` and embed their ``orders``.
|
||||
If we also want to get the total ``amount`` grouped by the ``order_date`` of the ``orders``, we would do the following:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -226,51 +222,20 @@ Continuing with the example relationship between ``orders`` and ``customers`` fr
|
||||
}
|
||||
]
|
||||
|
||||
In this example, the ``amount`` column is summed and grouped by the ``order_date`` *within* the context of the embedded resource. That is, the ``name``, ``city``, and ``state`` from the ``customers`` table have no bearing on the aggregation performed in the context of the ``orders`` association; instead, each aggregation can be seen as being performed independently on just the orders belonging to a particular customer, using only the data from the embedded resource for both grouping and aggregation.
|
||||
Note that the aggregate is done within the embedded resource ``orders``.
|
||||
It is not affected by any of the columns from the top-level relationship ``customers``.
|
||||
|
||||
Using Columns from a Spreaded Resource
|
||||
--------------------------------------
|
||||
Aggregates in To-One Spreads
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When you :ref:`spread an embedded resource <spread_embed>`, the columns from the spreaded resource are treated as if they were columns of the top-level resource, both when using them as grouping columns and when applying aggregate functions to them.
|
||||
|
||||
Grouping with Columns from a Spreaded Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For instance, assume you want to sum the ``amount`` column from the ``orders`` table, using the ``city`` and ``state`` columns from the ``customers`` table as grouping columns. To achieve this, you may select these two columns from the ``customers`` table and spread them; they will then be used as grouping columns:
|
||||
All the aggregates inside a :ref:`one-to-one or many-to-one spread embedded resource <spread_to_one_embed>` will be hoisted to the top-level relationship.
|
||||
In other words, it will behave as if the aggregate was done in the top-level relationship itself. For example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/orders?select=amount.sum(),...customers(city,state)
|
||||
curl "http://localhost:3000/orders?select=order_date,...customers(subscription_date.max(),subscription_date.min())
|
||||
|
||||
The result will be the same as if ``city`` and ``state`` were columns from the ``orders`` table:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
[
|
||||
{
|
||||
"sum": 2000.29,
|
||||
"city": "New York",
|
||||
"state": "NY"
|
||||
},
|
||||
{
|
||||
"sum": 9241.21,
|
||||
"city": "Los Angeles",
|
||||
"state": "CA"
|
||||
}
|
||||
]
|
||||
|
||||
Aggregate Functions with Columns from a Spreaded Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now imagine that the ``customers`` table has a ``joined_date`` column that represents the date that the customer joined. You want to get both the most recent and the oldest ``joined_date`` for customers that placed an order on every distinct order date. This can be expressed as follows:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/orders?select=order_date,...customers(joined_date.max(),joined_date.min())
|
||||
|
||||
As columns from a spreaded resource are treated as if they were columns from the top-level resource, the ``max()`` and ``min()`` are applied *within* the context of the top-level, rather than within the context of the embedded resource, as in the previous section.
|
||||
|
||||
The result will be the same as if the aggregations were applied to columns from the top-level:
|
||||
This will take the ``max`` and ``min`` subscription date of every customer and group it by the ``order_date`` column:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
@@ -286,3 +251,7 @@ The result will be the same as if the aggregations were applied to columns from
|
||||
"min": "2016-02-11"
|
||||
}
|
||||
]
|
||||
|
||||
.. note::
|
||||
|
||||
Aggregates inside to-many spreads are not supported
|
||||
|
||||
@@ -173,4 +173,4 @@ Domain Representations avoid all the above drawbacks. Their only drawback is tha
|
||||
|
||||
Why not create a `base type <https://www.postgresql.org/docs/current/sql-createtype.html#id-1.9.3.94.5.8>`_ instead? ``CREATE TYPE app_uuid (INTERNALLENGTH = 22, INPUT = app_uuid_parser, OUTPUT = app_uuid_formatter)``.
|
||||
|
||||
Creating base types need superuser, which is restricted on cloud hosted databases. Additionally this way lets “how the data is presented” dictate “how the data is stored” which would be backwards.
|
||||
Creating base types need superuser, which is restricted on cloud hosted databases. Additionally this way lets "how the data is presented" dictate "how the data is stored" which would be backwards.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Functions as RPC
|
||||
================
|
||||
|
||||
*"A single resource can be the equivalent of a database function, with the power to abstract state changes over any number of storage items"* -- `Roy T. Fielding <http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven#comment-743>`_
|
||||
*"A single resource can be the equivalent of a database function, with the power to abstract state changes over any number of storage items"* -- `Roy T. Fielding <https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven#comment-743>`_
|
||||
|
||||
Functions can perform any operation allowed by PostgreSQL (read data, modify data, :ref:`raise errors <raise_error>`, and even DDL operations). Every function in the :ref:`exposed schema <schemas>` and accessible by the :ref:`active database role <roles>` is executable under the :code:`/rpc` prefix.
|
||||
|
||||
@@ -71,6 +71,40 @@ The function parameter names match the JSON object keys in the POST case, for th
|
||||
|
||||
.. _function_single_json:
|
||||
|
||||
Functions with an array of JSON objects
|
||||
----------------------------------------------
|
||||
|
||||
If you want to pass multiple JSON objects to a Postgres function (an array of objects), you can create a function with a parameter of type ``json`` or ``jsonb``.
|
||||
|
||||
Within the curl request, this JSON must be embedded in an object where they key matches the same name as the function's ``json`` or ``jsonb`` parameter.
|
||||
This will allow you to loop over the array of JSON objects within the Postgres function.
|
||||
|
||||
This practice may allow you to reduce the number of ``curl`` requests required to accomplish a task.
|
||||
|
||||
For instance, assume we have created this function in the database.
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
CREATE FUNCTION update_data(p_json jsonb)
|
||||
RETURNS void AS $$
|
||||
DECLARE
|
||||
json_item json;
|
||||
BEGIN
|
||||
FOR json_item IN SELECT jsonb_array_elements(p_json) LOOP
|
||||
UPDATE data_table SET data_text_column = (json_item->>'data_text')::text
|
||||
WHERE data_int_column = (json_item->>'data_int')::integer;
|
||||
END LOOP;
|
||||
END;
|
||||
$$ LANGUAGE SQL IMMUTABLE;
|
||||
|
||||
A ``curl`` request using the POST method would look like the following:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/rpc/update_data" \
|
||||
-X POST -H "Content-Type: application/json" \
|
||||
-d '{ "p_json": [ { "data_text": "one", "data_int": "1" }, { "data_text": "two", "data_int": "2" } ] }'
|
||||
|
||||
Functions with a single unnamed JSON parameter
|
||||
----------------------------------------------
|
||||
|
||||
@@ -97,10 +131,6 @@ For this the ``Content-Type: application/json`` header must be included in the r
|
||||
|
||||
If an overloaded function has a single ``json`` or ``jsonb`` unnamed parameter, PostgREST will call this function as a fallback provided that no other overloaded function is found with the parameters sent in the POST request.
|
||||
|
||||
.. warning::
|
||||
|
||||
Sending the JSON request body as a single argument is also possible with :ref:`Prefer: params=single-object <prefer_params>` but this method is **deprecated**.
|
||||
|
||||
.. _function_single_unnamed:
|
||||
|
||||
Functions with a single unnamed parameter
|
||||
@@ -264,6 +294,23 @@ Let's get its :ref:`explain_plan` when calling it with filters applied:
|
||||
|
||||
Notice there's no "Function Scan" node in the plan, which tells us it has been inlined.
|
||||
|
||||
Horizontal Filtering
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Table-valued functions support horizontal filtering on selected and unselected columns.
|
||||
|
||||
For example, the following RPC with filter on unselected column returns:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/rpc/getallprojects?select=id,client_id&name=like.OSX"
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
[
|
||||
{ "id": 4, "client_id": 2 }
|
||||
]
|
||||
|
||||
.. _scalar_functions:
|
||||
|
||||
Scalar functions
|
||||
|
||||
@@ -19,6 +19,9 @@ For extra customization, the OpenAPI output contains a "description" field for e
|
||||
COMMENT ON TABLE monotremes IS
|
||||
'Freakish mammals lay the best eggs for breakfast';
|
||||
|
||||
COMMENT ON VIEW monotremes_v IS
|
||||
'Only the platypus is publicly visible';
|
||||
|
||||
COMMENT ON COLUMN monotremes.has_venomous_claw IS
|
||||
'Sometimes breakfast is not worth it';
|
||||
|
||||
|
||||
@@ -12,10 +12,9 @@ The following preferences are supported.
|
||||
- ``Prefer: return``. See :ref:`prefer_return`.
|
||||
- ``Prefer: count``. See :ref:`prefer_count`.
|
||||
- ``Prefer: resolution``. See :ref:`prefer_resolution`.
|
||||
- ``Prefer: missing``. See :ref:`bulk_insert_default`.
|
||||
- ``Prefer: missing``. See :ref:`prefer_missing`.
|
||||
- ``Prefer: max-affected``, See :ref:`prefer_max_affected`.
|
||||
- ``Prefer: tx``. See :ref:`prefer_tx`.
|
||||
- ``Prefer: params``. See :ref:`prefer_params`.
|
||||
|
||||
.. _prefer_handling:
|
||||
|
||||
@@ -197,12 +196,53 @@ The ``tx`` preference can be set to specify if the :ref:`transaction <transactio
|
||||
{"id": 35, "name": "Project X"}
|
||||
|
||||
|
||||
.. _prefer_missing:
|
||||
|
||||
Missing
|
||||
=======
|
||||
|
||||
When doing ``POST`` and ``PATCH`` requests, any missing columns in the payload will be inserted as ``null`` value by default. To use the ``DEFAULT`` column value instead, use the ``Prefer: missing=default`` header.
|
||||
|
||||
Having:
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
create table foo (
|
||||
id bigint generated by default as identity primary key
|
||||
, bar text
|
||||
, baz int default 100
|
||||
);
|
||||
|
||||
A request:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/foo?columns=id,bar,baz" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Prefer: missing=default, return=representation" \
|
||||
-d @- << EOF
|
||||
[
|
||||
{ "bar": "val1" },
|
||||
{ "bar": "val2", "baz": 15 }
|
||||
]
|
||||
EOF
|
||||
|
||||
Will result in:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
[
|
||||
{ "id": 1, "bar": "val1", "baz": 100 },
|
||||
{ "id": 2, "bar": "val2", "baz": 15 }
|
||||
]
|
||||
|
||||
|
||||
.. _prefer_max_affected:
|
||||
|
||||
Max Affected
|
||||
============
|
||||
|
||||
You can set a limit to the amount of resources affected in a request by sending ``max-affected`` preference. This feature works in combination with ``handling=strict`` preference. ``max-affected`` would be ignored with lenient handling. The "affected resources" are the number of rows returned by ``DELETE`` and ``PATCH`` requests. This is also supported through ``RPC`` calls.
|
||||
You can set a limit to the amount of resources affected in a request by sending ``max-affected`` preference. This feature works in combination with ``handling=strict`` preference. ``max-affected`` would be ignored with lenient handling. The "affected resources" are the number of rows returned by ``DELETE`` and ``PATCH`` requests.
|
||||
|
||||
To illustrate the use of this preference, consider the following scenario where the ``items`` table contains 14 rows.
|
||||
|
||||
@@ -225,30 +265,34 @@ To illustrate the use of this preference, consider the following scenario where
|
||||
"hint": null
|
||||
}
|
||||
|
||||
.. _prefer_params:
|
||||
|
||||
Single JSON object as Function Parameter
|
||||
----------------------------------------
|
||||
|
||||
.. warning::
|
||||
|
||||
Using this preference is **deprecated** in favor of :ref:`function_single_json`.
|
||||
|
||||
:code:`Prefer: params=single-object` allows sending the JSON request body as the single argument of a :ref:`function <functions>`.
|
||||
With :ref:`RPC <functions>`, the preference is honored completely on the basis of the number of rows returned in the result set of the function. This can be useful for complex mutation queries using `data-modifying statements <https://www.postgresql.org/docs/current/queries-with.html#QUERIES-WITH-MODIFYING>`_. A simple example:
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
CREATE FUNCTION mult_them(param json) RETURNS int AS $$
|
||||
SELECT (param->>'x')::int * (param->>'y')::int
|
||||
CREATE FUNCTION test.delete_items()
|
||||
RETURNS SETOF items AS $$
|
||||
DELETE FROM items WHERE id < 15 RETURNING *;
|
||||
$$ LANGUAGE SQL;
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/rpc/mult_them" \
|
||||
-X POST -H "Content-Type: application/json" \
|
||||
-H "Prefer: params=single-object" \
|
||||
-d '{ "x": 4, "y": 2 }'
|
||||
curl -i "http://localhost:3000/rpc/delete_items" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Prefer: handling=strict, max-affected=10"
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
HTTP/1.1 400 Bad Request
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
8
|
||||
{
|
||||
"code": "PGRST124",
|
||||
"message": "Query result exceeds max-affected preference constraint",
|
||||
"details": "The query affects 14 rows",
|
||||
"hint": null
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
It is important for functions to return ``SETOF`` or ``TABLE`` when called with ``max-affected`` preference. A violation of this would cause a :ref:`PGRST128 <pgrst128>` error.
|
||||
|
||||
@@ -143,7 +143,7 @@ Since the table name is plural, we can be more accurate by making it singular wi
|
||||
One-to-many relationships
|
||||
-------------------------
|
||||
|
||||
The **foreign key reference** establishes the inverse one-to-many relationship. In this case, ``films`` returns as a JSON array because of the “to-many” end.
|
||||
The **foreign key reference** establishes the inverse one-to-many relationship. In this case, ``films`` returns as a JSON array because of the "to-many" end.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -209,18 +209,25 @@ The join table is also detected if the composite key has additional columns.
|
||||
One-to-one relationships
|
||||
------------------------
|
||||
|
||||
One-to-one relationships are detected in two ways.
|
||||
One-to-one relationships are detected in two ways. (We'll use the ``films`` and ``technical_specs`` tables from the :ref:`sample film database <erd_film>` as an example).
|
||||
|
||||
- When the foreign key is a primary key as specified in the :ref:`sample film database <erd_film>`.
|
||||
- When the foreign key has a unique constraint.
|
||||
- When the foreign key is also a primary key.
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
create table technical_specs(
|
||||
film_id int references films(id) unique,
|
||||
runtime time,
|
||||
camera text,
|
||||
sound text
|
||||
film_id int references films(id) primary key
|
||||
-- ...
|
||||
);
|
||||
|
||||
- Or when the foreign key has a unique constraint.
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
create table technical_specs(
|
||||
id int primary key
|
||||
, film_id int references films(id) unique
|
||||
-- ...
|
||||
);
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -244,6 +251,12 @@ Computed Relationships
|
||||
|
||||
You can manually define relationships by using functions. This is useful for database objects that can't define foreign keys, like `Foreign Data Wrappers <https://wiki.postgresql.org/wiki/Foreign_data_wrappers>`_.
|
||||
|
||||
Computed relationships have good performance as their intended design enable `function inlining <https://wiki.postgresql.org/wiki/Inlining_of_SQL_functions#Inlining_conditions_for_table_functions>`_.
|
||||
|
||||
.. important::
|
||||
|
||||
- Always use ``SETOF`` when creating computed relationships. Functions can return a table without using ``SETOF``, but bear in mind that PostgreSQL will not inline them. e.g. ``RETURNS <table_name>`` is not inlinable.
|
||||
|
||||
Assuming there's a foreign table ``premieres`` that we want to relate to ``films``.
|
||||
|
||||
.. code-block:: postgres
|
||||
@@ -276,6 +289,10 @@ The name of the function ``film`` is arbitrary and can be used to do the embeddi
|
||||
".."
|
||||
]
|
||||
|
||||
.. warning::
|
||||
|
||||
- Make sure to correctly label the ``to-one`` part of the relationship. When using the ``ROWS 1`` estimation, PostgREST will expect a single row to be returned. If that is not the case, it will unnest the embedding and return repeated values for the top level resource.
|
||||
|
||||
Now let's define the opposite one-to-many relationship.
|
||||
|
||||
.. code-block:: postgres
|
||||
@@ -324,12 +341,6 @@ Thanks to overloaded functions, you can use the same function name for different
|
||||
|
||||
Computed relationships have good performance as their intended design enable `function inlining <https://wiki.postgresql.org/wiki/Inlining_of_SQL_functions#Inlining_conditions_for_table_functions>`_.
|
||||
|
||||
.. warning::
|
||||
|
||||
- Always use ``SETOF`` when creating computed relationships. Functions can return a table without using ``SETOF``, but bear in mind that PostgreSQL will not inline them.
|
||||
|
||||
- Make sure to correctly label the ``to-one`` part of the relationship. When using the ``ROWS 1`` estimation, PostgREST will expect a single row to be returned. If that is not the case, it will unnest the embedding and return repeated values for the top level resource.
|
||||
|
||||
.. _embed_disamb:
|
||||
.. _target_disamb:
|
||||
.. _hint_disamb:
|
||||
@@ -927,7 +938,12 @@ Filters can also be applied on nested embedded resources:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/films?select=*,roles(*,actors(*))&roles.actors.order=last_name&roles.actors.first_name=like.*Tom*"
|
||||
# curl "http://localhost:3000/films?select=*,roles(*,actors(*))&roles.actors.order=last_name&roles.actors.first_name=like.*Tom*"
|
||||
|
||||
curl --get "http://localhost:3000/films" \
|
||||
-d "select=*,roles(*,actors(*))" \
|
||||
-d "roles.actors.order=last_name" \
|
||||
-d "roles.actors.first_name=like.*Tom*"
|
||||
|
||||
The result will show the nested actors named Tom and order them by last name. Aliases can also be used instead of the resource names to filter the nested tables.
|
||||
|
||||
@@ -1138,14 +1154,19 @@ For example, to arrange the films in descending order using the director's last
|
||||
Spread embedded resource
|
||||
========================
|
||||
|
||||
On many-to-one and one-to-one relationships, you can "spread" the embedded resource. That is, remove the surrounding JSON object for the embedded resource columns.
|
||||
You can modify the shape of the embedded resources by using the spread syntax (``...``).
|
||||
|
||||
.. _spread_to_one_embed:
|
||||
|
||||
Spread To-One relationships
|
||||
---------------------------
|
||||
|
||||
Spread on resources forming :ref:`one-to-one <one-to-one>` and :ref:`many-to-one <many-to-one>` relationships, will lift the embedded columns to the top object.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# curl "http://localhost:3000/films?select=title,...directors(director_last_name:last_name)&title=like.*Workers*"
|
||||
|
||||
curl --get "http://localhost:3000/films" \
|
||||
-d "select=title,...directors(director_last_name:last_name)" \
|
||||
-d "select=title,...directors(director_first_name:first_name, director_last_name:last_name)" \
|
||||
-d "title=like.*Workers*"
|
||||
|
||||
.. code-block:: json
|
||||
@@ -1153,17 +1174,148 @@ On many-to-one and one-to-one relationships, you can "spread" the embedded resou
|
||||
[
|
||||
{
|
||||
"title": "Workers Leaving The Lumière Factory In Lyon",
|
||||
"director_first_name": "Louis",
|
||||
"director_last_name": "Lumière"
|
||||
}
|
||||
]
|
||||
|
||||
Note that there is no ``"directors"`` object. Also the embed columns can be aliased normally.
|
||||
Note that there is no wrapping ``"directors"`` object, unlike regularly embedding :ref:`many-to-one <many-to-one>` relationships. Also note that embedded columns can be aliased normally.
|
||||
|
||||
You can use this to get the columns of a join table in a many-to-many relationship. For instance, to get films and its actors, but including the ``character`` column from the roles table:
|
||||
.. _spread_to_many_embed:
|
||||
|
||||
Spread To-Many relationships
|
||||
----------------------------
|
||||
|
||||
Spread on resources forming :ref:`one-to-many <one-to-many>` and :ref:`many-to-many <many-to-many>` relationships, will convert the embedded columns into correlated arrays.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# curl "http://localhost:3000/films?select=title,actors:roles(character,...actors(first_name,last_name))&title=like.*Lighthouse*"
|
||||
curl --get "http://localhost:3000/directors" \
|
||||
-d "select=first_name,...films(film_titles:title,film_years:year)" \
|
||||
-d "first_name=like.Quentin*"
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
[
|
||||
{
|
||||
"first_name": "Quentin",
|
||||
"film_titles": [
|
||||
"Pulp Fiction",
|
||||
"Reservoir Dogs"
|
||||
],
|
||||
"film_years": [
|
||||
1994,
|
||||
1992
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
Note that ``films`` is no longer an array of objects, unlike regularly embedding :ref:`one-to-many`. The embedded columns become arrays and they're correlated-in the above result, we can say that "Pulp Fiction" premiered in 1994 and "Reservoir Dogs" in 1992.
|
||||
|
||||
Order in spread to-many
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In the above example, the order of the values inside the correlated arrays is unspecified, but all the values are guaranteed to be in the same unspecified order.
|
||||
|
||||
You can order the correlated arrays explicitly. For example, to order by the film year:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl --get "http://localhost:3000/directors" \
|
||||
-d "select=first_name,...films(film_titles:title,film_years:year)" \
|
||||
-d "first_name=like.Quentin*" \
|
||||
-d "films.order=year"
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
[
|
||||
{
|
||||
"first_name": "Quentin",
|
||||
"film_titles": [
|
||||
"Reservoir Dogs",
|
||||
"Pulp Fiction"
|
||||
],
|
||||
"film_years": [
|
||||
1992,
|
||||
1994
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
.. warning::
|
||||
|
||||
Aliasing spreaded columns is recommended since JSON allows duplicate keys. Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl --get "localhost:3000/projects" \
|
||||
-d "select=id,name,...clients(id,name)"
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
[{"id":1,"name":"Windows 7","id":1,"name":"Microsoft"},
|
||||
{"id":2,"name":"Windows 10","id":1,"name":"Microsoft"},
|
||||
{"id":3,"name":"IOS","id":2,"name":"Apple"},
|
||||
{"id":4,"name":"OSX","id":2,"name":"Apple"},
|
||||
{"id":5,"name":"Orphan","id":null,"name":null}]
|
||||
|
||||
This can be a problem in Javascript objects, since only the last duplicated key will be considered. To solve it do:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl --get "localhost:3000/projects" \
|
||||
-d "select=id,name,...clients(client_id:id,client_name:name)"
|
||||
|
||||
|
||||
Multiple Spreads
|
||||
----------------
|
||||
|
||||
You can use multiple spreads at any level. For example, let's spread ``technical_specs`` and ``roles`` into ``films`` and then spread ``films`` into ``directors``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl --get "http://localhost:3000/directors" \
|
||||
-d "select=first_name,...films(film_titles:title,film_years:year,...technical_specs(film_runtimes:runtime),...roles(film_characters:character))" \
|
||||
-d "first_name=like.Quentin*" \
|
||||
-d "films.order=year" \
|
||||
-d "films.roles.order=character"
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
[
|
||||
{
|
||||
"first_name": "Quentin",
|
||||
"film_titles": [
|
||||
"Reservoir Dogs",
|
||||
"Pulp Fiction"
|
||||
],
|
||||
"film_years": [
|
||||
1992,
|
||||
1994
|
||||
],
|
||||
"film_runtimes": [
|
||||
"01:39:00",
|
||||
"02:29:00"
|
||||
]
|
||||
"film_characters": [
|
||||
[ "Mr. Pink", "Mr. White" ],
|
||||
[ "Mia Wallace", "Vincent Vega" ]
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
Note that:
|
||||
|
||||
- All the ``film_*`` arrays are correlated-"Reservoir Dogs" premiered in 1992, its runtime is 1:39:00 and it has the following characters: ``[ "Mr. Pink", "Mr. White" ]``.
|
||||
- The ``film_*`` arrays are ordered by ``year`` (due to ``films.order=year``).
|
||||
- The bottom level array ``film_characters`` is ordered (due to ``films.roles.order=character``).
|
||||
|
||||
Spread a join table
|
||||
-------------------
|
||||
|
||||
Spread can be used to move the columns of a join table in a :ref:`many-to-many <many-to-many>` to the top object. For instance, to get the ``character`` column of the ``roles`` join table into ``actors``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl --get "http://localhost:3000/films" \
|
||||
-d "select=title,actors:roles(character,...actors(first_name,last_name))" \
|
||||
@@ -1184,6 +1336,4 @@ You can use this to get the columns of a join table in a many-to-many relationsh
|
||||
}
|
||||
]
|
||||
|
||||
.. note::
|
||||
|
||||
The spread operator ``...`` is borrowed from the Javascript `spread syntax <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax>`_.
|
||||
|
||||
@@ -16,6 +16,32 @@ Use the Accept request header to specify the acceptable format (or formats) for
|
||||
curl "http://localhost:3000/people" \
|
||||
-H "Accept: application/json"
|
||||
|
||||
.. note::
|
||||
|
||||
The ordering of columns in the response isn't guaranteed to align with the order specified in the ``select`` clause. For example, with resource embedding:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
http://localhost:3000/films?select=directors(last_name,id),title
|
||||
|
||||
We may get:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
[
|
||||
{
|
||||
"title": "title",
|
||||
"directors": {
|
||||
"id": 5,
|
||||
"last_name": "name"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
This is in line with the `JSON schema spec <https://json-schema.org/draft/2020-12/json-schema-core#name-instance-data-model>`_:
|
||||
|
||||
*"object: An unordered set of properties mapping a string to an instance"*
|
||||
|
||||
.. _builtin_media:
|
||||
|
||||
Builtin Media Type Handlers
|
||||
@@ -74,17 +100,15 @@ This returns
|
||||
|
||||
{ "id": 1 }
|
||||
|
||||
with a :code:`Content-Type: application/vnd.pgrst.object+json`.
|
||||
|
||||
When a singular response is requested but no entries are found, the server responds with an error message and 406 Not Acceptable status code rather than the usual empty array and 200 status:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"message": "JSON object requested, multiple (or no) rows returned",
|
||||
"details": "Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row",
|
||||
"hint": null,
|
||||
"code": "PGRST505"
|
||||
"code": "PGRST116",
|
||||
"message": "Cannot coerce the result to a single JSON object",
|
||||
"details": "The result contains 0 rows",
|
||||
"hint": null
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -72,7 +72,7 @@ imatch :code:`~*` ~* operator, see :ref:`pattern_matching`
|
||||
in :code:`IN` one of a list of values, e.g. :code:`?a=in.(1,2,3)`
|
||||
– also supports commas in quoted strings like
|
||||
:code:`?a=in.("hi,there","yes,you")`
|
||||
is :code:`IS` checking for exact equality (null,true,false,unknown)
|
||||
is :code:`IS` checking for exact equality (null,not_null,true,false,unknown)
|
||||
isdistinct :code:`IS DISTINCT FROM` not equal, treating :code:`NULL` as a comparable value
|
||||
fts :code:`@@` :ref:`fts` using to_tsquery
|
||||
plfts :code:`@@` :ref:`fts` using plainto_tsquery
|
||||
@@ -82,7 +82,7 @@ cs :code:`@>` contains e.g. :code:`?tags=cs.{example,
|
||||
cd :code:`<@` contained in e.g. :code:`?values=cd.{1,2,3}`
|
||||
ov :code:`&&` overlap (have points in common), e.g. :code:`?period=ov.[2017-01-01,2017-06-30]` –
|
||||
also supports array types, use curly braces instead of square brackets e.g.
|
||||
:code: `?arr=ov.{1,3}`
|
||||
:code:`?arr=ov.{1,3}`
|
||||
sl :code:`<<` strictly left of, e.g. :code:`?range=sl.(1,10)`
|
||||
sr :code:`>>` strictly right of
|
||||
nxr :code:`&<` does not extend to the right of, e.g. :code:`?range=nxr.(1,10)`
|
||||
@@ -175,25 +175,56 @@ To ensure best performance on larger data sets, an `appropriate index <https://w
|
||||
Full-Text Search
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The :code:`fts` filter mentioned above has a number of options to support flexible textual queries, namely the choice of plain vs phrase search and the language used for stemming. Suppose that :code:`tsearch` is a table with column :code:`my_tsv`, of type `tsvector <https://www.postgresql.org/docs/current/datatype-textsearch.html>`_. The following examples illustrate the possibilities.
|
||||
The :code:`fts` operator has a number of options to support flexible textual queries, namely the choice of plain vs phrase search and the language used for stemming.
|
||||
|
||||
The following examples illustrate the possibilities, assuming column :code:`my_tsv` is of type `tsvector <https://www.postgresql.org/docs/current/datatype-textsearch.html>`_.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/tsearch?my_tsv=fts(french).amusant"
|
||||
curl --get "http://localhost:3000/people" \
|
||||
-d "my_tsv=fts(french).amusant"
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/tsearch?my_tsv=plfts.The%20Fat%20Cats"
|
||||
curl --get "http://localhost:3000/people" \
|
||||
-d "my_tsv=plfts.The%20Fat%20Cats"
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/tsearch?my_tsv=not.phfts(english).The%20Fat%20Cats"
|
||||
curl --get "http://localhost:3000/people" \
|
||||
-d "my_tsv=not.phfts(english).The%20Fat%20Cats"
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/tsearch?my_tsv=not.wfts(french).amusant"
|
||||
curl --get "http://localhost:3000/people" \
|
||||
-d "my_tsv=not.wfts(french).amusant"
|
||||
|
||||
Using `websearch_to_tsquery` requires PostgreSQL of version at least 11.0 and will raise an error in earlier versions of the database.
|
||||
.. _fts_to_tsvector:
|
||||
|
||||
Automatic ``tsvector`` conversion
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If the filtered column is not of type ``tsvector``, then it will be automatically converted using `to_tsvector() <https://www.postgresql.org/docs/current/functions-textsearch.html#TEXTSEARCH-FUNCTIONS-TABLE>`_.
|
||||
This allows using the ``fts`` operator on ``text`` and ``json`` types out of the box.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl --get "http://localhost:3000/people" \
|
||||
-d "my_text_column=fts(french).amusant"
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl --get "http://localhost:3000/people" \
|
||||
-d "my_json_column=not.phfts(english).The%20Fat%20Cats"
|
||||
|
||||
.. important::
|
||||
|
||||
To ensure this operation is fast, you need to create an index on the expression:
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
CREATE INDEX idx_people_col ON people
|
||||
USING GIN (to_tsvector('french', my_text_column));
|
||||
|
||||
.. _v_filter:
|
||||
|
||||
@@ -525,45 +556,6 @@ To bulk insert JSON post an array of objects having all-matching keys
|
||||
]
|
||||
EOF
|
||||
|
||||
.. _bulk_insert_default:
|
||||
|
||||
Bulk Insert with Default Values
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Any missing columns in the payload will be inserted as ``null`` values. To use the ``DEFAULT`` column value instead, use the ``Prefer: missing=default`` header.
|
||||
|
||||
Having:
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
create table foo (
|
||||
id bigint generated by default as identity primary key
|
||||
, bar text
|
||||
, baz int default 100
|
||||
);
|
||||
|
||||
A request:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/foo?columns=id,bar,baz" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Prefer: missing=default, return=representation" \
|
||||
-d @- << EOF
|
||||
[
|
||||
{ "bar": "val1" },
|
||||
{ "bar": "val2", "baz": 15 }
|
||||
]
|
||||
EOF
|
||||
|
||||
Will result in:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
[
|
||||
{ "id": 1, "bar": "val1", "baz": 100 },
|
||||
{ "id": 2, "bar": "val2", "baz": 15 }
|
||||
]
|
||||
|
||||
.. _specify_columns:
|
||||
|
||||
@@ -606,7 +598,13 @@ To update a row or rows in a table, use the PATCH verb. Use :ref:`h_filter` to s
|
||||
-X PATCH -H "Content-Type: application/json" \
|
||||
-d '{ "category": "child" }'
|
||||
|
||||
Updates also support :ref:`prefer_return`, :ref:`resource_embedding` and :ref:`v_filter`.
|
||||
Updates also support:
|
||||
|
||||
- :ref:`prefer_return`
|
||||
- :ref:`resource_embedding`
|
||||
- :ref:`v_filter`
|
||||
- :ref:`Missing Preference <prefer_missing>`
|
||||
- :ref:`specify_columns`
|
||||
|
||||
.. warning::
|
||||
|
||||
@@ -623,18 +621,34 @@ You can make an upsert with :code:`POST` and the :code:`Prefer: resolution=merge
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/employees" \
|
||||
curl "http://localhost:3000/products" \
|
||||
-X POST -H "Content-Type: application/json" \
|
||||
-H "Prefer: resolution=merge-duplicates" \
|
||||
-d @- << EOF
|
||||
[
|
||||
{ "id": 1, "name": "Old employee 1", "salary": 30000 },
|
||||
{ "id": 2, "name": "Old employee 2", "salary": 42000 },
|
||||
{ "id": 3, "name": "New employee 3", "salary": 50000 }
|
||||
{ "sku": "CL2031", "name": "Existing T-shirt", "price": 35 },
|
||||
{ "sku": "CL2040", "name": "Existing Hoodie", "price": 60 },
|
||||
{ "sku": "AC1022", "name": "New Cap", "price": 30 }
|
||||
]
|
||||
EOF
|
||||
|
||||
By default, upsert operates based on the primary key columns, you must specify all of them. You can also choose to ignore the duplicates with :code:`Prefer: resolution=ignore-duplicates`. This works best when the primary key is natural, but it's also possible to use it if the primary key is surrogate (example: "id serial primary key"). For more details read `this issue <https://github.com/PostgREST/postgrest/issues/1118>`_.
|
||||
By default, upsert operates based on the primary key columns, so you must specify all of them.
|
||||
You can also choose to ignore the duplicates with :code:`Prefer: resolution=ignore-duplicates`.
|
||||
Upsert works best when the primary key is natural (e.g. ``sku``).
|
||||
However, it can work with surrogate primary keys (e.g. ``id serial primary key``), if you also do a :ref:`bulk_insert` with :ref:`prefer_missing`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3000/employees?colums=id,name,salary" \
|
||||
-X POST -H "Content-Type: application/json" \
|
||||
-H "Prefer: resolution=merge-duplicates, missing=default" \
|
||||
-d @- << EOF
|
||||
[
|
||||
{ "id": 1, "name": "Existing employee 1", "salary": 30000 },
|
||||
{ "id": 2, "name": "Existing employee 2", "salary": 42000 },
|
||||
{ "name": "New employee 3", "salary": 50000 }
|
||||
]
|
||||
EOF
|
||||
|
||||
.. important::
|
||||
After creating a table or changing its primary key, you must refresh PostgREST schema cache for upsert to work properly. To learn how to refresh the cache see :ref:`schema_reloading`.
|
||||
@@ -700,31 +714,6 @@ Deletions also support :ref:`prefer_return`, :ref:`resource_embedding` and :ref:
|
||||
|
||||
Beware of accidentally deleting all rows in a table. To learn to prevent that see :ref:`block_fulltable`.
|
||||
|
||||
.. _limited_update_delete:
|
||||
|
||||
Limited Update/Delete
|
||||
=====================
|
||||
|
||||
You can limit the amount of affected rows by :ref:`update` or :ref:`delete` with the ``limit`` query parameter. For this, you must add an explicit ``order`` on a unique column(s).
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl -X PATCH "/users?limit=10&order=id&last_login=lt.2020-01-01" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "status": "inactive" }'
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl -X DELETE "http://localhost:3000/users?limit=10&order=id&status=eq.inactive"
|
||||
|
||||
If your table has no unique columns, you can use the `ctid <https://www.postgresql.org/docs/current/ddl-system-columns.html>`_ system column.
|
||||
|
||||
Using ``offset`` to target a different subset of rows is also possible.
|
||||
|
||||
.. note::
|
||||
|
||||
There is no native ``UPDATE...LIMIT`` or ``DELETE...LIMIT`` support in PostgreSQL; the generated query simulates that behavior and is based on `this Crunchy Data blog post <https://www.crunchydata.com/blog/simulating-update-or-delete-with-limit-in-postgres-ctes-to-the-rescue>`_.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<script type="text/javascript">
|
||||
@@ -739,6 +728,7 @@ Using ``offset`` to target a different subset of rows is also possible.
|
||||
'#estimated-count': 'pagination_count.html#estimated-count',
|
||||
'#prefer-return-headers-only': 'preferences.html#headers-only',
|
||||
'#prefer-return-representation': 'preferences.html#full',
|
||||
'#bulk-insert-default': 'preferences.html#prefer-missing',
|
||||
};
|
||||
|
||||
let willRedirectTo = redirects[hash];
|
||||
|
||||
@@ -14,7 +14,7 @@ Custom Queries
|
||||
|
||||
The PostgREST URL grammar limits the kinds of queries clients can perform. It prevents arbitrary, potentially poorly constructed and slow client queries. It's good for quality of service, but means database administrators must create custom views and functions to provide richer endpoints. The most common causes for custom endpoints are
|
||||
|
||||
* Table unions
|
||||
* SET operators like `UNION, INTERSECT and EXCEPT <https://www.postgresql.org/docs/current/queries-union.html>`_.
|
||||
* More complicated joins than those provided by :ref:`resource_embedding`.
|
||||
* Geo-spatial queries that require an argument, like "points near (lat,lon)"
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ The authenticator role is used for connecting to the database and should be conf
|
||||
.. _user_impersonation:
|
||||
|
||||
User Impersonation
|
||||
------------------
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The picture below shows how the server handles authentication. If auth succeeds, it switches into the user role specified by the request, otherwise it switches into the anonymous role (if it's set in :ref:`db-anon-role`).
|
||||
|
||||
@@ -43,12 +43,13 @@ This role switching mechanism is called **user impersonation**. In PostgreSQL it
|
||||
|
||||
The impersonated roles will have their settings applied. See :ref:`impersonated_settings`.
|
||||
|
||||
.. _jwt_impersonation:
|
||||
.. _jwt_auth:
|
||||
|
||||
JWT-Based User Impersonation
|
||||
----------------------------
|
||||
JWT Authentication
|
||||
------------------
|
||||
|
||||
We use `JSON Web Tokens <https://jwt.io/>`_ to authenticate API requests, this allows us to be stateless and not require database lookups for verification. As you'll recall a JWT contains a list of cryptographically signed claims. All claims are allowed but PostgREST cares specifically about a claim called role.
|
||||
We use `JSON Web Tokens <https://datatracker.ietf.org/doc/html/rfc7519/>`_ to authenticate API requests, this allows us to be stateless and not require database lookups for verification.
|
||||
As you'll recall a JWT contains a list of cryptographically signed claims. All claims are allowed but PostgREST cares specifically about a claim called role (configurable with :ref:`jwt_role_extract`).
|
||||
|
||||
.. code:: json
|
||||
|
||||
@@ -72,17 +73,10 @@ Note that the database administrator must allow the authenticator role to switch
|
||||
|
||||
If the client included no JWT (or one without a role claim) then PostgREST switches into the anonymous role. The database administrator must set the anonymous role permissions correctly to prevent anonymous users from seeing or changing things they shouldn't.
|
||||
|
||||
.. _jwt_generation:
|
||||
.. _bearer_auth:
|
||||
|
||||
JWT Generation
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
You can create a valid JWT either from inside your database (see :ref:`sql_user_management`) or via an external service (see :ref:`external_jwt`).
|
||||
|
||||
.. _client_auth:
|
||||
|
||||
Client Auth
|
||||
~~~~~~~~~~~
|
||||
Bearer Authentication
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To make an authenticated request the client must include an :code:`Authorization` HTTP header with the value :code:`Bearer <jwt>`. For instance:
|
||||
|
||||
@@ -93,24 +87,29 @@ To make an authenticated request the client must include an :code:`Authorization
|
||||
|
||||
The ``Bearer`` header value can be used with or without capitalization(``bearer``).
|
||||
|
||||
.. _jwt_caching:
|
||||
.. _jwt_generation:
|
||||
|
||||
JWT Caching
|
||||
-----------
|
||||
JWT Generation
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
PostgREST validates ``JWTs`` on every request. We can cache ``JWTs`` to avoid this performance overhead.
|
||||
You can create a valid JWT either from inside your database (see :ref:`sql_user_management`) or via an external service (see :ref:`external_auth`).
|
||||
|
||||
To enable JWT caching, the config :code:`jwt-cache-max-lifetime` is to be set. It is the maximum number of seconds for which the cache stores the JWT validation results. The cache uses the :code:`exp` claim to set the cache entry lifetime. If the JWT does not have an :code:`exp` claim, it uses the config value. See :ref:`jwt-cache-max-lifetime` for more details.
|
||||
.. _jwt_signature:
|
||||
|
||||
.. note::
|
||||
JWT Signature Verification
|
||||
--------------------------
|
||||
|
||||
You can use the :ref:`server-timing_header` to see the effect of JWT caching.
|
||||
PostgREST supports both symmetric and asymmetric keys for verifying the signature of the token.
|
||||
|
||||
Symmetric Keys
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Each token is cryptographically signed with a secret key. In the case of symmetric cryptography the signer and verifier share the same secret passphrase, which can be configured with :ref:`jwt-secret`.
|
||||
If it is set to a simple string value like “reallyreallyreallyreallyverysafe” then PostgREST interprets it as an HMAC-SHA256 passphrase.
|
||||
In the case of symmetric cryptography the signer and verifier share the same secret passphrase, which can be configured with :ref:`jwt-secret`.
|
||||
If it is set to a simple string then PostgREST interprets it as an HMAC-SHA256 passphrase.
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
jwt-secret = "reallyreallyreallyreallyverysafe"
|
||||
|
||||
.. _asym_keys:
|
||||
|
||||
@@ -156,13 +155,112 @@ You can specify the literal value as we saw earlier, or reference a filename to
|
||||
|
||||
jwt-secret = "@rsa.jwk.pub"
|
||||
|
||||
JWT Claims Validation
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
``kid`` verification
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
PostgREST honors the :code:`exp` claim for token expiration, rejecting expired tokens.
|
||||
PostgREST has built-in verification of the `key ID parameter <https://www.rfc-editor.org/rfc/rfc7517#section-4.5>`_, useful when working with a JSON Web Key Set.
|
||||
It goes as follows:
|
||||
|
||||
- If the JWT contains a ``kid`` parameter, then PostgREST will look for the JSON Web Key in the :ref:`jwt-secret`.
|
||||
|
||||
+ If no key has a matching ``kid`` (or if they don't have one defined), the token will be rejected with a :ref:`401 Unauthorized <pgrst301>` error.
|
||||
+ If a key matches the ``kid`` value then it will validate the token against that key accordingly.
|
||||
|
||||
- If the JWT doesn't have a ``kid``, PostgREST will try each key in the :ref:`jwt-secret` one by one until it finds one that works.
|
||||
|
||||
.. _jwt_claims_validation:
|
||||
|
||||
JWT Claims Validation
|
||||
---------------------
|
||||
|
||||
Time-Based claims validation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The time-based JWT claims specified in `RFC 7519 <https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4>`_ are validated:
|
||||
|
||||
- ``exp`` Expiration Time
|
||||
- ``iat`` Issued At
|
||||
- ``nbf`` Not Before
|
||||
|
||||
We allow a 30-second clock skew when validating the above claims. In other words, we give an extra 30 seconds before the JWT is rejected if there is a slight discrepancy in the timestamps.
|
||||
|
||||
.. _jwt_aud:
|
||||
|
||||
``aud`` validation
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
PostgREST has built-in validation of the `JWT audience claim <https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3>`_.
|
||||
It works this way:
|
||||
|
||||
- If :ref:`jwt-aud` is not set (the default), PostgREST identifies with all audiences and allows the JWT for any ``aud`` claim.
|
||||
- If :ref:`jwt-aud` is set to a specific audience, PostgREST will check if this audience is present in the ``aud`` claim:
|
||||
|
||||
+ If the ``aud`` value is a JSON string, it will match it to the :ref:`jwt-aud`.
|
||||
+ If the ``aud`` value is a JSON array of strings, it will search every element for a match.
|
||||
+ If the match fails or if the ``aud`` value is not a string or array of strings, then the token will be rejected with a :ref:`401 Unauthorized <pgrst303>` error.
|
||||
+ If the ``aud`` key **is not present** or if its value is ``null`` or ``[]``, PostgREST will interpret this token as allowed for all audiences and will complete the request.
|
||||
|
||||
.. _jwt_caching:
|
||||
|
||||
JWT Cache
|
||||
---------
|
||||
|
||||
JWT signature validation (specially :ref:`asym_keys` such as RSA) is slow, we can cache ``JWT`` validation results to avoid this performance overhead.
|
||||
|
||||
The JWT cache is bounded and uses the `SIEVE algorithm <https://cachemon.github.io/SIEVE-website>`_ for efficient eviction. The cache is enabled by default and can be configured with :ref:`jwt-cache-max-entries`.
|
||||
|
||||
It's recommended to leave the JWT cache enabled as our load tests indicate ~20% more throughput for simple GET requests when using it. This while reducing CPU utilization in exchange for a bit more memory.
|
||||
|
||||
:ref:`jwt_cache_metrics` are available.
|
||||
|
||||
.. note::
|
||||
|
||||
- If the ``jwt-secret`` is changed and the config is reloaded, the JWT cache will reset.
|
||||
- JWTs that pass :ref:`jwt_signature` are cached, regardless if they pass :ref:`jwt_claims_validation`. We do this to ensure responses stays fast under common failure cases (such as expired JWTs).
|
||||
- You can use the :ref:`server-timing_header` to see the peformance benefit of JWT caching.
|
||||
|
||||
.. _jwt_role_extract:
|
||||
|
||||
JWT Role Extraction
|
||||
-------------------
|
||||
|
||||
A JSPath DSL that specifies the location of the :code:`role` key in the JWT claims. It's configured by :ref:`jwt-role-claim-key`. This can be used to consume a JWT provided by a third party service like Auth0, Okta, Microsoft Entra or Keycloak.
|
||||
|
||||
The DSL follows the `JSONPath <https://goessner.net/articles/JsonPath/>`_ expression grammar with extended string comparison operators. Supported operators are:
|
||||
|
||||
- ``==`` selects the first array element that exactly matches the right operand
|
||||
- ``!=`` selects the first array element that does not match the right operand
|
||||
- ``^==`` selects the first array element that starts with the right operand
|
||||
- ``==^`` selects the first array element that ends with the right operand
|
||||
- ``*==`` selects the first array element that contains the right operand
|
||||
|
||||
Usage examples:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# {"postgrest":{"roles": ["other", "author"]}}
|
||||
# the DSL accepts characters that are alphanumerical or one of "_$@" as keys
|
||||
jwt-role-claim-key = ".postgrest.roles[1]"
|
||||
|
||||
# {"https://www.example.com/role": { "key": "author" }}
|
||||
# non-alphanumerical characters can go inside quotes(escaped in the config value)
|
||||
jwt-role-claim-key = ".\"https://www.example.com/role\".key"
|
||||
|
||||
# {"postgrest":{"roles": ["other", "author"]}}
|
||||
# `@` represents the current element in the array
|
||||
# all the these match the string "author"
|
||||
jwt-role-claim-key = ".postgrest.roles[?(@ == \"author\")]"
|
||||
jwt-role-claim-key = ".postgrest.roles[?(@ != \"other\")]"
|
||||
jwt-role-claim-key = ".postgrest.roles[?(@ ^== \"aut\")]"
|
||||
jwt-role-claim-key = ".postgrest.roles[?(@ ==^ \"hor\")]"
|
||||
jwt-role-claim-key = ".postgrest.roles[?(@ *== \"utho\")]"
|
||||
|
||||
.. note::
|
||||
|
||||
The string comparison operators are implemented as a custom extension to the JSPath and does not strictly follow the `RFC 9535 <https://www.rfc-editor.org/rfc/rfc9535.html>`_.
|
||||
|
||||
JWT Security
|
||||
~~~~~~~~~~~~
|
||||
------------
|
||||
|
||||
There are at least three types of common critiques against using JWT: 1) against the standard itself, 2) against using libraries with known security vulnerabilities, and 3) against using JWT for web sessions. We'll briefly explain each critique, how PostgREST deals with it, and give recommendations for appropriate user action.
|
||||
|
||||
@@ -198,3 +296,23 @@ doing custom logic based on the web user info.
|
||||
END IF;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<script type="text/javascript">
|
||||
let hash = window.location.hash;
|
||||
|
||||
const redirects = {
|
||||
'#jwt-based-user-impersonation': '#jwt-authentication',
|
||||
'#client-auth': '#bearer-authentication',
|
||||
'#jwt-caching': '#jwt-cache',
|
||||
'#jwk-kid-validation': '#kid-verification',
|
||||
'#jwt-aud-claim-validation': '#aud-validation',
|
||||
};
|
||||
|
||||
let willRedirectTo = redirects[hash];
|
||||
|
||||
if (willRedirectTo) {
|
||||
window.location.href = willRedirectTo;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -3,23 +3,47 @@
|
||||
CLI
|
||||
===
|
||||
|
||||
PostgREST provides a CLI with the commands listed below:
|
||||
PostgREST provides a CLI with the options listed below:
|
||||
|
||||
.. code:: text
|
||||
|
||||
Usage: postgrest [-v|--version] [-e|--example] [--dump-config | --dump-schema | --ready]
|
||||
[FILENAME]
|
||||
|
||||
PostgREST / create a REST API to an existing Postgres
|
||||
database
|
||||
|
||||
Available options:
|
||||
-h,--help Show this help text
|
||||
-v,--version Show the version information
|
||||
-e,--example Show an example configuration file
|
||||
--dump-config Dump loaded configuration and exit
|
||||
--dump-schema Dump loaded schema as JSON and exit (for debugging,
|
||||
output structure is unstable)
|
||||
--ready Checks the health of PostgREST by doing a request on
|
||||
the admin server /ready endpoint
|
||||
FILENAME Path to configuration file
|
||||
|
||||
FILENAME
|
||||
--------
|
||||
|
||||
Runs PostgREST with the given :ref:`file_config`.
|
||||
|
||||
Help
|
||||
----
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ postgrest [-h|--help]
|
||||
$ postgrest --help
|
||||
|
||||
Shows all the commands available.
|
||||
Shows all the options available.
|
||||
|
||||
Version
|
||||
-------
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ postgrest [-v|--version]
|
||||
$ postgrest --version
|
||||
|
||||
Prints the PostgREST version.
|
||||
|
||||
@@ -28,16 +52,16 @@ Example
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ postgrest [-e|--example]
|
||||
$ postgrest --example
|
||||
|
||||
Shows example configuration options.
|
||||
Shows example configuration settings.
|
||||
|
||||
Dump Config
|
||||
-----------
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ postgrest [--dump-config]
|
||||
$ postgrest --dump-config
|
||||
|
||||
Dumps the loaded :ref:`configuration` values, considering the configuration file, environment variables and :ref:`in_db_config`.
|
||||
|
||||
@@ -46,6 +70,20 @@ Dump Schema
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ postgrest [--dump-schema]
|
||||
$ postgrest --dump-schema
|
||||
|
||||
Dumps the schema cache in JSON format.
|
||||
|
||||
Ready Flag
|
||||
----------
|
||||
|
||||
Makes a request to the ``/ready`` endpoint of the :ref:`admin_server`. It exits with a return code of ``0`` on success and ``1`` on failure.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ postgrest --ready
|
||||
OK: http://localhost:3001/ready
|
||||
|
||||
.. note::
|
||||
|
||||
The ``--ready`` flag cannot be used when :ref:`server-host` is configured with special hostnames. We suggest to change it to ``localhost``.
|
||||
|
||||
@@ -135,19 +135,32 @@ To reload the configuration via signal, send a SIGUSR2 signal to the server proc
|
||||
Configuration Reload with NOTIFY
|
||||
--------------------------------
|
||||
|
||||
To reload the configuration from within the database, you can use a NOTIFY command.
|
||||
To reload the configuration from within the database, you can use the ``NOTIFY`` command. See :ref:`listener`.
|
||||
|
||||
.. code:: postgresql
|
||||
|
||||
NOTIFY pgrst, 'reload config'
|
||||
|
||||
The ``"pgrst"`` notification channel is enabled by default. You can name the channel with :ref:`db-channel` and enable or disable it with :ref:`db-channel-enabled`.
|
||||
|
||||
.. _config_full_list:
|
||||
|
||||
List of parameters
|
||||
==================
|
||||
|
||||
.. _admin-server-host:
|
||||
|
||||
admin-server-host
|
||||
-----------------
|
||||
|
||||
=============== =======================
|
||||
**Type** String
|
||||
**Default** `server-host` value
|
||||
**Reloadable** N
|
||||
**Environment** PGRST_ADMIN_SERVER_HOST
|
||||
**In-Database** `n/a`
|
||||
=============== =======================
|
||||
|
||||
Specifies the host for the :ref:`admin_server`. Defaults to :ref:`server-host` value.
|
||||
|
||||
.. _admin-server-port:
|
||||
|
||||
admin-server-port
|
||||
@@ -161,7 +174,7 @@ admin-server-port
|
||||
**In-Database** `n/a`
|
||||
=============== =======================
|
||||
|
||||
Specifies the port for the :ref:`admin_server`.
|
||||
Specifies the port for the :ref:`admin_server`. Cannot be equal to :ref:`server-port`.
|
||||
|
||||
.. _app.settings.*:
|
||||
|
||||
@@ -178,6 +191,10 @@ app.settings.*
|
||||
|
||||
Arbitrary settings that can be used to pass in secret keys directly as strings, or via OS environment variables. For instance: :code:`app.settings.jwt_secret = "$(MYAPP_JWT_SECRET)"` will take :code:`MYAPP_JWT_SECRET` from the environment and make it available to PostgreSQL functions as :code:`current_setting('app.settings.jwt_secret')`.
|
||||
|
||||
When using the environment variable `PGRST_APP_SETTINGS_*` form, the remainder of the variable is used as the new name. Case is not important : :code:`PGRST_APP_SETTINGS_MY_ENV_VARIABLE=some_value` can be accessed in postgres as :code:`current_setting('app.settings.my_env_variable')`.
|
||||
|
||||
The :code:`current_setting` function has `an optional boolean second <https://www.postgresql.org/docs/current/functions-admin.html#FUNCTIONS-ADMIN-SET>`_ argument to avoid it from raising an error if the value was not defined. Default values to :code:`app.settings` can then be given by combining this argument with :code:`coalesce` and :code:`nullif` : :code:`coalesce(nullif(current_setting('app.settings.my_custom_variable', true), ''), 'default value')`. The use of :code:`nullif` is necessary because if set in a transaction, the setting is sometimes not "rolled back" to :code:`null`. See also :ref:`this section <guc_req_headers_cookies_claims>` for more information on this behaviour.
|
||||
|
||||
.. _db-aggregates-enabled:
|
||||
|
||||
db-aggregates-enabled
|
||||
@@ -298,6 +315,10 @@ db-extra-search-path
|
||||
|
||||
Multiple schemas can be added in a comma-separated string, e.g. ``public, extensions``.
|
||||
|
||||
.. important::
|
||||
|
||||
We default this config to ``public`` because it is the most common schema used to install PostgreSQL extensions such as :ref:`PostGIS <ww_postgis>`. You can disable this by setting this config to ``""``.
|
||||
|
||||
.. _db-hoisted-tx-settings:
|
||||
|
||||
db-hoisted-tx-settings
|
||||
@@ -388,7 +409,7 @@ db-pool-max-idletime
|
||||
**In-Database** `n/a`
|
||||
=============== =================================
|
||||
|
||||
*For backwards compatibility, this config parameter is also available as “db-pool-timeout”.*
|
||||
*For backwards compatibility, this config parameter is also available as "db-pool-timeout".*
|
||||
|
||||
Time in seconds to close idle pool connections.
|
||||
|
||||
@@ -582,11 +603,7 @@ jwt-aud
|
||||
**In-Database** pgrst.jwt_aud
|
||||
=============== =================================
|
||||
|
||||
Specifies the `JWT audience claim <https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3>`_. If this claim is present in the client provided JWT then you must set this to the same value as in the JWT, otherwise verifying the JWT will fail.
|
||||
|
||||
.. warning::
|
||||
|
||||
Using this setting will only reject tokens with a different audience claim. Tokens **without** audience claim will still be accepted.
|
||||
Specifies an audience for the JWT ``aud`` claim. See :ref:`jwt_aud`.
|
||||
|
||||
.. _jwt-role-claim-key:
|
||||
|
||||
@@ -603,17 +620,7 @@ jwt-role-claim-key
|
||||
|
||||
*For backwards compatibility, this config parameter is also available without prefix as "role-claim-key".*
|
||||
|
||||
A JSPath DSL that specifies the location of the :code:`role` key in the JWT claims. This can be used to consume a JWT provided by a third party service like Auth0, Okta or Keycloak. Usage examples:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# {"postgrest":{"roles": ["other", "author"]}}
|
||||
# the DSL accepts characters that are alphanumerical or one of "_$@" as keys
|
||||
jwt-role-claim-key = ".postgrest.roles[1]"
|
||||
|
||||
# {"https://www.example.com/role": { "key": "author }}
|
||||
# non-alphanumerical characters can go inside quotes(escaped in the config value)
|
||||
jwt-role-claim-key = ".\"https://www.example.com/role\".key"
|
||||
See :ref:`jwt_role_extract` on how to specify key paths and usage examples.
|
||||
|
||||
.. _jwt-secret:
|
||||
|
||||
@@ -651,20 +658,20 @@ jwt-secret-is-base64
|
||||
|
||||
When this is set to :code:`true`, the value derived from :code:`jwt-secret` will be treated as a base64 encoded secret.
|
||||
|
||||
.. _jwt-cache-max-lifetime:
|
||||
.. _jwt-cache-max-entries:
|
||||
|
||||
jwt-cache-max-lifetime
|
||||
jwt-cache-max-entries
|
||||
----------------------
|
||||
|
||||
=============== =================================
|
||||
**Type** Int
|
||||
**Default** 0
|
||||
**Default** 1000
|
||||
**Reloadable** Y
|
||||
**Environment** PGRST_JWT_CACHE_MAX_LIFETIME
|
||||
**In-Database** pgrst.jwt_cache_max_lifetime
|
||||
**Environment** PGRST_JWT_CACHE_MAX_ENTRIES
|
||||
**In-Database** pgrst.jwt_cache_max_entries
|
||||
=============== =================================
|
||||
|
||||
Maximum number of seconds of lifetime for cached entries. The default :code:`0` disables caching. See :ref:`jwt_caching`.
|
||||
Maximum number of entries in JWT cache. The value :code:`0` disables JWT caching. See :ref:`jwt_caching`.
|
||||
|
||||
.. _log-level:
|
||||
|
||||
@@ -696,10 +703,26 @@ log-level
|
||||
log-level = "info"
|
||||
|
||||
# All the above plus events for development purposes are logged
|
||||
# Logs connection pool events and the schema cache parsing time
|
||||
log-level = "debug"
|
||||
|
||||
Because currently there's no buffering for logging, the levels with minimal logging(``crit/error``) will increase throughput.
|
||||
|
||||
.. _log-query:
|
||||
|
||||
log-query
|
||||
---------
|
||||
|
||||
=============== =================================
|
||||
**Type** Boolean
|
||||
**Default** False
|
||||
**Reloadable** Y
|
||||
**Environment** PGRST_LOG_QUERY
|
||||
**In-Database** `n/a`
|
||||
=============== =================================
|
||||
|
||||
Logs the SQL query for the corresponding request at the current :ref:`log-level`. See :ref:`sql_query_logs`.
|
||||
|
||||
.. _openapi-mode:
|
||||
|
||||
openapi-mode
|
||||
@@ -813,6 +836,12 @@ server-host
|
||||
* :code:`*6` - any IPv4 or IPv6 hostname, IPv6 preferred
|
||||
* :code:`!6` - any IPv6 hostname
|
||||
|
||||
Examples:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
server-host = "127.0.0.1"
|
||||
|
||||
.. _server-port:
|
||||
|
||||
server-port
|
||||
@@ -856,7 +885,7 @@ server-timing-enabled
|
||||
**In-Database** pgrst.server_timing_enabled
|
||||
=============== =================================
|
||||
|
||||
Enables the `Server-Timing <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing>`_ header.
|
||||
Enables the `Server-Timing <https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Server-Timing>`_ header.
|
||||
See :ref:`server-timing_header`.
|
||||
|
||||
.. _server-unix-socket:
|
||||
|
||||
@@ -15,7 +15,7 @@ Dynamic Connection Pool
|
||||
|
||||
To conserve system resources, PostgREST uses a dynamic connection pool. This enables the number of connections in the pool to increase and decrease depending on request traffic.
|
||||
|
||||
- If all the connections are being used, a new connection is added. The pool can grow until it reaches the :ref:`db-pool` size. Note that it’s pointless to set this higher than the ``max_connections`` setting in your database.
|
||||
- If all the connections are being used, a new connection is added. The pool can grow until it reaches the :ref:`db-pool` size. Note that it's pointless to set this higher than the ``max_connections`` setting in your database.
|
||||
- If a connection is unused for a period of time (:ref:`db-pool-max-idletime`), it will be released.
|
||||
- For connecting to the database, the :ref:`authenticator <roles>` role is used. You can configure this using :ref:`db-uri`.
|
||||
|
||||
@@ -106,4 +106,4 @@ Also set :ref:`db-channel-enabled` to ``false`` since ``LISTEN`` is not compatib
|
||||
|
||||
.. note::
|
||||
|
||||
It’s not recommended to use an external connection pooler. `Our benchmarks <https://github.com/PostgREST/postgrest/issues/2294#issuecomment-1139148672>`_ indicate it provides much lower performance than PostgREST built-in pool.
|
||||
It's not recommended to use an external connection pooler. `Our benchmarks <https://github.com/PostgREST/postgrest/issues/2294#issuecomment-1139148672>`_ indicate it provides much lower performance than PostgREST built-in pool.
|
||||
|
||||
@@ -5,6 +5,8 @@ Errors
|
||||
|
||||
PostgREST error messages follow the PostgreSQL error structure. It includes ``MESSAGE``, ``DETAIL``, ``HINT``, ``ERRCODE`` and will add an HTTP status code to the response.
|
||||
|
||||
.. _postgresql_errors:
|
||||
|
||||
Errors from PostgreSQL
|
||||
======================
|
||||
|
||||
@@ -205,14 +207,6 @@ Related to the HTTP request elements.
|
||||
| | | specified in the ``select`` part of the query string. |
|
||||
| PGRST108 | | See :ref:`embed_filters`. |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst109: | 400 | Restricting a Deletion or an Update using limits must |
|
||||
| | | include the ordering of a unique column. |
|
||||
| PGRST109 | | See :ref:`limited_update_delete`. |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst110: | 400 | When restricting a Deletion or an Update using limits |
|
||||
| | | modifies more rows than the maximum specified in the limit. |
|
||||
| PGRST110 | | See :ref:`limited_update_delete`. |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst111: | 500 | An invalid ``response.headers`` was set. |
|
||||
| | | See :ref:`guc_resp_hdrs`. |
|
||||
| PGRST111 | | |
|
||||
@@ -241,10 +235,6 @@ Related to the HTTP request elements.
|
||||
| | | there is no many-to-one or one-to-one relationship between |
|
||||
| PGRST118 | | them. |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst119: | 400 | Could not use the spread operator on the related table |
|
||||
| | | because there is no many-to-one or one-to-one relationship |
|
||||
| PGRST119 | | between them. |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst120: | 400 | An embedded resource can only be filtered using the |
|
||||
| | | ``is.null`` or ``not.is.null`` :ref:`operators <operators>`.|
|
||||
| PGRST120 | | |
|
||||
@@ -257,6 +247,31 @@ Related to the HTTP request elements.
|
||||
| | | ``Prefer: handling=strict``. See :ref:`prefer_handling`. |
|
||||
| PGRST122 | | |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst123: | 400 | Aggregate functions are disabled. |
|
||||
| | | See :ref:`db-aggregates-enabled`. |
|
||||
| PGRST123 | | |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst124: | 400 | ``max-affected`` preference is violated. |
|
||||
| | | See :ref:`prefer_max_affected`. |
|
||||
| PGRST124 | | |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst125: | 404 | Invalid path is specified in request URL. |
|
||||
| | | |
|
||||
| PGRST125 | | |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst126: | 404 | Open API config is disabled but API root path is |
|
||||
| | | accessed. See :ref:`openapi-mode`. |
|
||||
| PGRST126 | | |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst127: | 400 | The feature specified in the ``details`` field is not |
|
||||
| | | implemented. |
|
||||
| PGRST127 | | |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst128: | 400 | ``max-affected`` preference is violated with ``RPC`` call. |
|
||||
| | | See :ref:`prefer_max_affected`. |
|
||||
| PGRST128 | | |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
|
||||
|
||||
.. _pgrst2**:
|
||||
|
||||
@@ -290,6 +305,10 @@ Related to a :ref:`schema_cache`. Most of the time, these errors are solved by :
|
||||
| | | in the ``columns`` query parameter is not found. |
|
||||
| PGRST204 | | |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst205: | 404 | Caused when the :ref:`table specified <tables_views>` in |
|
||||
| | | the URI is not found. |
|
||||
| PGRST205 | | |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
|
||||
.. _pgrst3**:
|
||||
|
||||
@@ -305,14 +324,18 @@ Related to the authentication process using JWT. You can follow the :ref:`tut1`
|
||||
| | | configuration. |
|
||||
| PGRST300 | | |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst301: | 401 | Any error related to the verification of the JWT, |
|
||||
| | | which means that the JWT provided is invalid in some way. |
|
||||
| .. _pgrst301: | 401 | Provided JWT couldn't be decoded or it is invalid. |
|
||||
| | | |
|
||||
| PGRST301 | | |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst302: | 401 | Attempted to do a request without |
|
||||
| | | :ref:`authentication <client_auth>` when the anonymous role |
|
||||
| | | :ref:`bearer_auth` when the anonymous role |
|
||||
| PGRST302 | | is disabled by not setting it in :ref:`db-anon-role`. |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
| .. _pgrst303: | 401 | :ref:`JWT claims validation <jwt_claims_validation>` |
|
||||
| | | or parsing failed. |
|
||||
| PGRST303 | | |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
|
||||
.. The Internal Errors Group X** is always at the end
|
||||
|
||||
@@ -331,6 +354,8 @@ Internal errors. If you encounter any of these, you may have stumbled on a Postg
|
||||
| PGRSTX00 | | |
|
||||
+---------------+-------------+-------------------------------------------------------------+
|
||||
|
||||
.. _custom_errors:
|
||||
|
||||
Custom Errors
|
||||
=============
|
||||
|
||||
@@ -427,3 +452,24 @@ For non standard HTTP status, you can optionally add ``status_text`` to describe
|
||||
detail = '{"status":419,"status_text":"Page Expired","headers":{"X-Powered-By":"Nerd Rage"}}';
|
||||
|
||||
If PostgREST can't parse the JSON objects ``message`` and ``detail``, it will throw a ``PGRST121`` error. See :ref:`Errors from PostgREST<pgrst1**>`.
|
||||
|
||||
.. _proxy-status_header:
|
||||
|
||||
Proxy-Status Header
|
||||
===================
|
||||
|
||||
For error cases, the standard `Proxy-Status <https://www.rfc-editor.org/rfc/rfc9209.html#name-the-proxy-status-http-field>`_ header is returned with the error code. The error code comes from either :ref:`PostgREST <pgrst_errors>`, :ref:`PostgreSQL <postgresql_errors>` or :ref:`Custom <custom_errors>` errors. This is useful when doing ``HEAD`` requests where the HTTP status is not descriptive enough.
|
||||
|
||||
For example, doing a request on a table with high count (say 30_000_000), we get:
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
HEAD /table HTTP/1.1
|
||||
Prefer: count=exact
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
HTTP/1.1 500 Internal Server Error
|
||||
Proxy-Status: PostgREST; error=57014
|
||||
|
||||
The PostgreSQL error code ``57014`` (`ref <https://www.postgresql.org/docs/current/errcodes-appendix.html>`_) reveals that the error is due to a short ``statement_timeout`` value.
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
.. _listener:
|
||||
|
||||
Listener
|
||||
########
|
||||
|
||||
PostgREST uses `LISTEN <https://www.postgresql.org/docs/current/sql-listen.html>`_ to reload its :ref:`Schema Cache <schema_reloading_notify>` and :ref:`Configuration <config_reloading_notify>` via `NOTIFY <https://www.postgresql.org/docs/current/sql-notify.html>`_.
|
||||
This is useful in environments where you can't send SIGUSR1 or SIGUSR2 Unix Signals.
|
||||
Like on cloud managed containers or on Windows systems.
|
||||
|
||||
.. code:: postgresql
|
||||
|
||||
NOTIFY pgrst, 'reload schema'; -- reload schema cache
|
||||
NOTIFY pgrst, 'reload config'; -- reload config
|
||||
NOTIFY pgrst; -- reload both
|
||||
|
||||
By default, the LISTEN channel is enabled (:ref:`db-channel-enabled`) and named ``pgrst`` (:ref:`db-channel`).
|
||||
|
||||
Listener on Read Replicas
|
||||
=========================
|
||||
|
||||
|
||||
The ``LISTEN`` and ``NOTIFY`` commands do not work on PostgreSQL read replicas.
|
||||
Thus, if you connect PostgREST to a read replica the Listener will fail to start.
|
||||
|
||||
.. code:: psql
|
||||
|
||||
-- check if the instance is a replica
|
||||
postgres=# select pg_is_in_recovery();
|
||||
pg_is_in_recovery
|
||||
-------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
postgres=# LISTEN pgrst;
|
||||
ERROR: cannot execute LISTEN during recovery
|
||||
|
||||
To work around this, you can connect the Listener to the primary while still using the :ref:`connection_pool` on the replica.
|
||||
|
||||
This can be done by using the standard `libpq multiple hosts <https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-MULTIPLE-HOSTS>`_ and `target_session_attrs <https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-TARGET-SESSION-ATTRS>`_ in your :ref:`connection string <db-uri>`.
|
||||
|
||||
.. code:: bash
|
||||
|
||||
db-uri = "postgres://read_replica.host,primary.host/mydb?target_session_attrs=read-only"
|
||||
|
||||
This will cause the :ref:`connection_pool` to connect to the read replica host and ``LISTEN`` on the fallback primary host.
|
||||
|
||||
.. note::
|
||||
|
||||
- Under the hood, PostgREST forces `target_session_attrs=read-write <https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-TARGET-SESSION-ATTRS>`_ for the ``LISTEN`` session.
|
||||
So if you specify ``target_session_attrs=read-only`` as mentioned above, PostgREST will override it for the ``LISTEN``.
|
||||
- ``read-only`` is only available on libpq >= 14, if you use a lower version you will get an error like ``invalid target_session_attrs value: \"read-only\"``.
|
||||
|
||||
.. _listener_automatic_recovery:
|
||||
|
||||
Automatic Recovery
|
||||
==================
|
||||
|
||||
The listener will retry reconnecting to the database if connection loss happens.
|
||||
|
||||
- It will retry forever with exponential backoff, with a maximum backoff time of 32 seconds between retries. Each of these attempts are :ref:`logged <pgrst_logging>`.
|
||||
- Automatic recovery can be disabled by setting :ref:`db-pool-automatic-recovery` to ``false``.
|
||||
- To ensure a valid state, the listener reloads the :ref:`schema_cache` and :ref:`configuration` when recovering.
|
||||
@@ -15,28 +15,68 @@ Observability allows measuring a system's current state based on the data it gen
|
||||
Logs
|
||||
====
|
||||
|
||||
PostgREST logs basic request information to ``stdout``, including the authenticated user if available, the requesting IP address and user agent, the URL requested, and HTTP response status.
|
||||
PostgREST logs basic request information to ``stdout``, including the authenticated user if available, the requesting IP address and user agent, the URL requested, the HTTP response status and the response body size in bytes if available.
|
||||
|
||||
With :ref:`log-level` set to ``info``, we get:
|
||||
|
||||
.. code::
|
||||
|
||||
127.0.0.1 - user [26/Jul/2021:01:56:38 -0500] "GET /clients HTTP/1.1" 200 - "" "curl/7.64.0"
|
||||
127.0.0.1 - anonymous [26/Jul/2021:01:56:48 -0500] "GET /unexistent HTTP/1.1" 404 - "" "curl/7.64.0"
|
||||
127.0.0.1 - user [26/Jul/2021:01:56:38 -0500] "GET /clients HTTP/1.1" 200 56 "" "curl/7.64.0"
|
||||
127.0.0.1 - anonymous [26/Jul/2021:01:56:48 -0500] "GET /unexistent HTTP/1.1" 404 162 "" "curl/7.64.0"
|
||||
|
||||
For diagnostic information about the server itself, PostgREST logs to ``stderr``. It includes the server version and also the version of the connected PostgreSQL.
|
||||
For diagnostic information about the server itself, PostgREST logs to ``stderr``:
|
||||
|
||||
- The full version of the connected PostgreSQL database.
|
||||
- :ref:`schema_cache` statistics.
|
||||
- The messages received by the :ref:`listener`.
|
||||
|
||||
.. code::
|
||||
|
||||
06/May/2024:08:16:11 -0500: Starting PostgREST 12.1...
|
||||
06/May/2024:08:16:11 -0500: Attempting to connect to the database...
|
||||
06/May/2024:08:16:11 -0500: Successfully connected to PostgreSQL 14.10 (Ubuntu 14.10-0ubuntu0.22.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit
|
||||
06/May/2024:08:16:11 -0500: Listening on port 3000
|
||||
06/May/2024:08:16:11 -0500: Connection Pool initialized with a maximum size of 10 connections
|
||||
06/May/2024:08:16:11 -0500: API server listening on port 3000
|
||||
06/May/2024:08:16:11 -0500: Listening for database notifications on the "pgrst" channel
|
||||
06/May/2024:08:16:11 -0500: Config reloaded
|
||||
06/May/2024:08:16:11 -0500: Schema cache queried in 3.8 milliseconds
|
||||
06/May/2024:08:16:11 -0500: Schema cache loaded 15 Relations, 8 Relationships, 8 RPCs, 0 Domain Representations, 4 Media Type Handlers
|
||||
06/May/2024:14:11:27 -0500: Received a config reload message on the "pgrst" channel
|
||||
06/May/2024:14:11:27 -0500: Config reloaded
|
||||
|
||||
.. note::
|
||||
|
||||
Logs are based on the ``log-level`` setting. See :ref:`log-level`.
|
||||
|
||||
.. _sql_query_logs:
|
||||
|
||||
SQL Query Logs
|
||||
--------------
|
||||
|
||||
To log the SQL queries executed for a request, set the :ref:`log-query` to ``true``. It will be logged based on the current :ref:`log-level` setting.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
log-level = "warn"
|
||||
log-query = "true"
|
||||
|
||||
The SQL queries will only be logged on ``400`` HTTP errors and up.
|
||||
So, if the user requests a resource without sufficient privileges:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "localhost:3000/protected_table"
|
||||
|
||||
This will be logged by PostgREST:
|
||||
|
||||
.. code::
|
||||
|
||||
17/Feb/2025:17:28:15 -0500: WITH pgrst_source AS ( SELECT "public"."protected_table".* FROM "public"."protected_table" ) SELECT null::bigint AS total_result_set, pg_catalog.count(_postgrest_t) AS page_total, coalesce(json_agg(_postgrest_t), '[]') AS body, nullif(current_setting('response.headers', true), '') AS response_headers, nullif(current_setting('response.status', true), '') AS response_status, '' AS response_inserted FROM ( SELECT * FROM pgrst_source ) _postgrest_t
|
||||
127.0.0.1 - web_anon [17/Feb/2025:17:28:15 -0500] "GET /protected_table HTTP/1.1" 401 99 "" "curl/8.7.1"
|
||||
|
||||
Database Logs
|
||||
-------------
|
||||
|
||||
Currently PostgREST doesn't log the SQL commands executed against the underlying database.
|
||||
|
||||
To find the SQL operations, you can watch the database logs. By default PostgreSQL does not keep these logs, so you'll need to make the configuration changes below.
|
||||
Additionally, to find all the SQL operations, you can watch the database logs. By default PostgreSQL does not keep these logs, so you'll need to make the configuration changes below.
|
||||
|
||||
Find :code:`postgresql.conf` inside your PostgreSQL data directory (to find that, issue the command :code:`show data_directory;`). Either find the settings scattered throughout the file and change them to the following values, or append this block of code to the end of the configuration file.
|
||||
|
||||
@@ -80,12 +120,17 @@ Restart the database and watch the log file in real-time to understand how HTTP
|
||||
Metrics
|
||||
=======
|
||||
|
||||
The ``metrics`` endpoint on the :ref:`admin_server` endpoint provides metrics in `Prometheus text format <https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format>`_.
|
||||
The ``metrics`` endpoint on the :ref:`admin_server` endpoint provides metrics in `Prometheus text format <https://prometheus.io/docs/instrumenting/exposition_formats/#prometheus-text-format>`_.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl "http://localhost:3001/metrics"
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
# HELP pgrst_schema_cache_query_time_seconds The query time in seconds of the last schema cache load
|
||||
# TYPE pgrst_schema_cache_query_time_seconds gauge
|
||||
pgrst_schema_cache_query_time_seconds 1.5937927e-2
|
||||
@@ -159,6 +204,40 @@ pgrst_db_pool_max
|
||||
|
||||
Max pool connections.
|
||||
|
||||
.. _jwt_cache_metrics:
|
||||
|
||||
JWT Cache Metrics
|
||||
-----------------
|
||||
|
||||
Metrics related to the :ref:`jwt_caching`.
|
||||
|
||||
pgrst_jwt_cache_requests_total
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
======== =======
|
||||
**Type** Counter
|
||||
======== =======
|
||||
|
||||
The total number of JWT cache lookups.
|
||||
|
||||
pgrst_jwt_cache_hits_total
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
======== =======
|
||||
**Type** Counter
|
||||
======== =======
|
||||
|
||||
The total number of JWT cache hits.
|
||||
|
||||
pgrst_jwt_cache_evictions_total
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
======== =======
|
||||
**Type** Counter
|
||||
======== =======
|
||||
|
||||
The total number of JWT cache evictions.
|
||||
|
||||
Traces
|
||||
======
|
||||
|
||||
@@ -194,12 +273,17 @@ You can enable tracing HTTP requests by setting :ref:`server-trace-header`. Spec
|
||||
HTTP/1.1 200 OK
|
||||
X-Request-Id: 123
|
||||
|
||||
Proxy-Status Header
|
||||
-------------------
|
||||
|
||||
See :ref:`proxy-status_header`.
|
||||
|
||||
.. _server-timing_header:
|
||||
|
||||
Server-Timing Header
|
||||
--------------------
|
||||
|
||||
You can enable the `Server-Timing <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing>`_ header by setting :ref:`server-timing-enabled` on.
|
||||
You can enable the `Server-Timing <https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Server-Timing>`_ header by setting :ref:`server-timing-enabled` on.
|
||||
This header communicates metrics of the different phases in the request-response cycle.
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -213,7 +297,7 @@ This header communicates metrics of the different phases in the request-response
|
||||
Server-Timing: jwt;dur=14.9, parse;dur=71.1, plan;dur=109.0, transaction;dur=353.2, response;dur=4.4
|
||||
|
||||
- All the durations (``dur``) are in milliseconds.
|
||||
- The ``jwt`` stage is when :ref:`jwt_impersonation` is done. This duration can be lowered with :ref:`jwt_caching`.
|
||||
- The ``jwt`` stage is when :ref:`jwt_auth` is done. This duration can be lowered with :ref:`jwt_caching`.
|
||||
- On the ``parse`` stage, the :ref:`url_grammar` is parsed.
|
||||
- On the ``plan`` stage, the :ref:`schema_cache` is used to generate the :ref:`main_query` of the transaction.
|
||||
- The ``transaction`` stage corresponds to the database transaction. See :ref:`transactions`.
|
||||
@@ -223,6 +307,27 @@ This header communicates metrics of the different phases in the request-response
|
||||
|
||||
We're working on lowering the duration of the ``parse`` and ``plan`` stages on https://github.com/PostgREST/postgrest/issues/2816.
|
||||
|
||||
.. _content-length_header:
|
||||
|
||||
Content-Length Header
|
||||
---------------------
|
||||
|
||||
You can verify the response body size in bytes in the `Content-Length header <https://httpwg.org/specs/rfc9110.html#field.content-length>`_.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl -i 'localhost:3000/users'
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Length: 104
|
||||
|
||||
Note that this header won't be returned on ``HEAD`` requests for optimization purposes (see :ref:`head_req`).
|
||||
This is in line with `RFC 9110 <https://httpwg.org/specs/rfc9110.html#field.content-length>`_.
|
||||
|
||||
The body size is also present in the :ref:`PostgREST logs <pgrst_logging>`.
|
||||
|
||||
.. _explain_plan:
|
||||
|
||||
Execution plan
|
||||
|
||||
@@ -47,15 +47,24 @@ For docker you can do:
|
||||
Schema Cache Reloading with NOTIFY
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
PostgREST also allows you to reload its schema cache through PostgreSQL `NOTIFY <https://www.postgresql.org/docs/current/sql-notify.html>`_.
|
||||
To reload the schema cache from within the database, you can use the ``NOTIFY`` command. See :ref:`listener`.
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
NOTIFY pgrst, 'reload schema'
|
||||
|
||||
This is useful in environments where you can’t send the SIGUSR1 Unix Signal. Like on cloud managed containers or on Windows systems.
|
||||
Debouncing
|
||||
~~~~~~~~~~
|
||||
|
||||
The ``pgrst`` notification channel is enabled by default. For configuring the channel, see :ref:`db-channel` and :ref:`db-channel-enabled`.
|
||||
PostgREST does not reload the schema cache for each notification when several ``NOTIFY pgrst`` events are generated quickly after one another.
|
||||
|
||||
There are two cases to consider: when notifications are sent within a single transaction and when they are sent across multiple transactions.
|
||||
|
||||
In the first case, PostgreSQL deduplicates identical ``NOTIFY`` events within the same transaction. This means that even if multiple ``NOTIFY pgrst`` statements are executed before a ``COMMIT``, only a single notification is delivered to PostgREST.
|
||||
|
||||
In the second case, when notifications are sent from separate transactions in a short time span, PostgREST applies a debouncing mechanism to avoid excessive schema cache reloads.
|
||||
|
||||
Instead of reloading the schema cache for each notification, events are grouped within a small time window of 100 milliseconds. The reload function is executed once immediately when the first notification is received and once more after the burst of events settles, resulting in at most two executions within that time window.
|
||||
|
||||
.. _auto_schema_reloading:
|
||||
|
||||
|
||||
@@ -284,11 +284,10 @@ However, starting from PostgreSQL 15, you can grant privileges for these setting
|
||||
|
||||
GRANT SET ON PARAMETER <setting> TO <authenticator>;
|
||||
|
||||
Function Settings
|
||||
~~~~~~~~~~~~~~~~~
|
||||
Hoisted Function Settings
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In addition to :ref:`impersonated_settings`, PostgREST will also apply function settings as transaction-scoped settings. This allows functions settings to override
|
||||
the impersonated and connection role settings.
|
||||
PostgREST can "hoist" function settings to transaction-scoped settings. This allows functions settings to override the impersonated and connection role settings.
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
@@ -303,7 +302,7 @@ When calling the above function (see :ref:`functions`), the statement timeout wi
|
||||
|
||||
.. note::
|
||||
|
||||
Only the transactions that are hoisted by config :ref:`db-hoisted-tx-settings` will be applied.
|
||||
Only the settings in :ref:`db-hoisted-tx-settings` will be hoisted.
|
||||
|
||||
.. _main_query:
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
docutils==0.20.1
|
||||
sphinx-copybutton
|
||||
sphinx-intl
|
||||
sphinx-rtd-theme>=0.5.1
|
||||
sphinx-rtd-dark-mode>=1.3.0
|
||||
sphinx-tabs>=3.2.0
|
||||
sphinx>=5.0.2
|
||||
sphinxext-opengraph==0.9.1
|
||||
urllib3==2.2.1
|
||||
# This file is auto-generated by postgrest-nixpkgs-upgrade
|
||||
sphinx==8.2.3
|
||||
sphinx-copybutton==0.5.2
|
||||
sphinx-rtd-dark-mode==1.3.0
|
||||
sphinx-rtd-theme==3.0.2
|
||||
sphinx-tabs==3.4.7
|
||||
sphinxext-opengraph==0.9.1
|
||||
@@ -28,13 +28,24 @@
|
||||
|
||||
pacman -S postgrest
|
||||
|
||||
.. tab:: Nix
|
||||
.. tab:: Nix via nixpkgs
|
||||
|
||||
You can install PostgREST from nixpkgs.
|
||||
|
||||
.. code:: bash
|
||||
|
||||
nix-env -i haskellPackages.postgrest
|
||||
nix-env -i postgrest
|
||||
|
||||
.. tab:: Nix via flake
|
||||
|
||||
You can install PostgREST via flake.
|
||||
|
||||
.. code:: nix
|
||||
|
||||
{
|
||||
inputs.postgrest.url = "github:postgrest/postgrest";
|
||||
# ...
|
||||
}
|
||||
|
||||
.. group-tab:: Windows
|
||||
|
||||
|
||||
@@ -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:
|
||||
@@ -218,12 +213,8 @@ You should see something similar to:
|
||||
.. code-block:: text
|
||||
|
||||
Starting PostgREST 12.0.2...
|
||||
Attempting to connect to the database...
|
||||
Connection successful
|
||||
Listening on port 3000
|
||||
Config reloaded
|
||||
Listening for notifications on the pgrst channel
|
||||
Schema cache loaded
|
||||
Successfully connected to PostgreSQL 14.10 (Ubuntu 14.10-0ubuntu0.22.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit
|
||||
API server listening on port 3000
|
||||
|
||||
It's now ready to serve web requests. There are many nice graphical API exploration tools you can use, but for this tutorial we'll use :code:`curl` because it's likely to be installed on your system already. Open a new terminal (leaving the one open that PostgREST is running inside). Try doing an HTTP request for the todos.
|
||||
|
||||
|
||||
@@ -52,17 +52,31 @@ Check that the :code:`tutorial.conf` (created in the previous tutorial) has the
|
||||
|
||||
If the PostgREST server is still running from the previous tutorial, restart it to load the updated configuration file.
|
||||
|
||||
.. _tut1_step3:
|
||||
|
||||
Step 3. Sign a Token
|
||||
--------------------
|
||||
|
||||
Ordinarily your own code in the database or in another server will create and sign authentication tokens, but for this tutorial we will make one "by hand." Go to `jwt.io <https://jwt.io/#debugger-io>`_ and fill in the fields like this:
|
||||
Ordinarily your own code in the database or in another server will create and sign authentication tokens, but for this tutorial we will make one "by hand" using ``bash`` and ``openssl``.
|
||||
|
||||
.. figure:: ../_static/tuts/tut1-jwt-io.png
|
||||
:alt: jwt.io interface
|
||||
.. code:: bash
|
||||
|
||||
How to create a token at https://jwt.io
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
**Remember to fill in the secret you generated rather than the word "secret".** After you have filled in the secret and payload, the encoded data on the left will update. Copy the encoded token.
|
||||
JWT_SECRET='test_secret_that_is_at_least_32_characters_long'
|
||||
|
||||
_base64 () { openssl base64 -e -A | tr '+/' '-_' | tr -d '='; }
|
||||
|
||||
header=$(echo -n '{"alg":"HS256","typ":"JWT"}' | _base64)
|
||||
|
||||
payload=$(echo -n "{\"role\":\"todo_user\"}" | _base64)
|
||||
|
||||
signature=$(echo -n "$header.$payload" | openssl dgst -sha256 -hmac "$JWT_SECRET" -binary | _base64)
|
||||
|
||||
echo -n "$header.$payload.$signature"
|
||||
|
||||
**Remember to fill in the secret you generated rather than keeping the "test_secret_that_is_at_least_32_characters_long".** After you have filled in the secret and payload, the encoded data on the left will update. Copy the encoded token.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -145,14 +159,22 @@ To observe expiration in action, we'll add an :code:`exp` claim of five minutes
|
||||
|
||||
select extract(epoch from now() + '5 minutes'::interval) :: integer;
|
||||
|
||||
Go back to jwt.io and change the payload to
|
||||
Or in ``bash``:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"role": "todo_user",
|
||||
"exp": 123456789
|
||||
}
|
||||
.. code-block:: bash
|
||||
|
||||
exp=$(( EPOCHSECONDS + 5*60 )) # five minutes
|
||||
|
||||
echo $exp
|
||||
|
||||
Go back to :ref:`tut1_step3` and change the payload to
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
payload=$(echo -n "{\"role\":\"todo_user\",\"exp\":\"123456789\"}" | _base64)
|
||||
|
||||
echo -n "$header.$payload.$signature"
|
||||
|
||||
**NOTE**: Don't forget to change the dummy epoch value :code:`123456789` in the snippet above to the epoch value returned by the :code:`psql` command.
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1752006229,
|
||||
"narHash": "sha256-BeuAPwNM2RBc5bvUTb0j4GRs2yBkDeRCw/8Y3v9Xesc=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c80edd02003fe3d8af527215a3ac069be9cfd47f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixpkgs-25.05-darwin",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
description = "REST API for any Postgres database";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-25.05-darwin";
|
||||
};
|
||||
|
||||
nixConfig = {
|
||||
extra-substituters = "https://postgrest.cachix.org";
|
||||
extra-trusted-public-keys = "postgrest.cachix.org-1:icgW4R15fz1+LqvhPjt4EnX/r19AaqxiVV+1olwlZtI=";
|
||||
};
|
||||
|
||||
outputs = { nixpkgs, ... }:
|
||||
let
|
||||
systems = [
|
||||
"aarch64-darwin"
|
||||
"aarch64-linux"
|
||||
"x86_64-darwin"
|
||||
"x86_64-linux"
|
||||
];
|
||||
|
||||
pgrstFor = system: import ./default.nix {
|
||||
inherit system;
|
||||
nixpkgsVersion = {
|
||||
owner = "nixos";
|
||||
repo = "nixpkgs";
|
||||
inherit (nixpkgs) rev;
|
||||
tarballHash = nixpkgs.narHash;
|
||||
};
|
||||
};
|
||||
|
||||
genSystems = f: nixpkgs.lib.genAttrs systems (system: f (pgrstFor system));
|
||||
in
|
||||
{
|
||||
packages = genSystems (attrs: {
|
||||
default = attrs.postgrestPackage.bin;
|
||||
profiled = attrs.postgrestProfiled.bin;
|
||||
} // nixpkgs.lib.optionalAttrs (attrs ? postgrestStatic) {
|
||||
static = attrs.postgrestStatic;
|
||||
});
|
||||
|
||||
apps = genSystems (attrs: {
|
||||
default = {
|
||||
type = "app";
|
||||
program = "${attrs.postgrestStatic or attrs.postgrestPackage.bin}/bin/postgrest";
|
||||
meta.description = "REST API for any Postgres database";
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -72,45 +72,53 @@ The PostgREST utilities available in `nix-shell` all have names that begin with
|
||||
```bash
|
||||
# Note: The utilities listed here might not be up to date.
|
||||
[nix-shell]$ postgrest-<tab>
|
||||
postgrest-build postgrest-test-spec
|
||||
postgrest-check postgrest-watch
|
||||
postgrest-clean postgrest-with-all
|
||||
postgrest-coverage postgrest-with-postgresql-10
|
||||
postgrest-lint postgrest-with-postgresql-11
|
||||
postgrest-run postgrest-with-postgresql-12
|
||||
postgrest-style postgrest-with-postgresql-13
|
||||
postgrest-style-check postgrest-with-postgresql-9.6
|
||||
postgrest-test-io
|
||||
postgrest-build postgrest-parallel-curl
|
||||
postgrest-check postgrest-profiled-run
|
||||
postgrest-clean postgrest-push-cachix
|
||||
postgrest-commitlint postgrest-release
|
||||
postgrest-coverage postgrest-repl
|
||||
postgrest-coverage-draft-overlay postgrest-run
|
||||
postgrest-docs-build postgrest-style
|
||||
postgrest-docs-check postgrest-style-check
|
||||
postgrest-docs-dictcheck postgrest-test-big-schema
|
||||
postgrest-docs-linkcheck postgrest-test-doctests
|
||||
postgrest-docs-render postgrest-test-io
|
||||
postgrest-docs-serve postgrest-test-memory
|
||||
postgrest-docs-spellcheck postgrest-test-replica
|
||||
postgrest-dump-minimal-imports postgrest-test-spec
|
||||
postgrest-dump-schema postgrest-test-spec-idempotence
|
||||
postgrest-gen-ctags postgrest-watch
|
||||
postgrest-gen-jwt postgrest-with-all
|
||||
postgrest-gen-secret postgrest-with-git
|
||||
postgrest-git-hooks postgrest-with-pgrst
|
||||
postgrest-hsie-graph-modules postgrest-with-pg-13
|
||||
postgrest-hsie-graph-symbols postgrest-with-pg-14
|
||||
postgrest-hsie-minimal-imports postgrest-with-pg-15
|
||||
postgrest-lint postgrest-with-pg-16
|
||||
postgrest-loadtest postgrest-with-pg-17
|
||||
postgrest-loadtest-against postgrest-with-slow-pg
|
||||
postgrest-loadtest-report postgrest-with-slow-postgrest
|
||||
postgrest-nixpkgs-upgrade
|
||||
...
|
||||
|
||||
[nix-shell]$
|
||||
|
||||
```
|
||||
|
||||
Some additional modules like `memory`, `docker` and `release`
|
||||
have large dependencies that would need to be built before the shell becomes
|
||||
The `docker` module has large dependencies to be build before the shell becomes
|
||||
available, which could take an especially long time if the cachix binary cache
|
||||
is not used. You can activate those by passing a flag to `nix-shell` with
|
||||
`nix-shell --arg <module> true`. This will make the respective utilities available:
|
||||
is not used. You can activate it by passing a flag to `nix-shell` with
|
||||
`nix-shell --arg docker true`. This will make the respective utilities available:
|
||||
|
||||
```bash
|
||||
$ nix-shell --arg memory true
|
||||
[nix-shell]$ postgrest-<tab>
|
||||
postgrest-build postgrest-test-spec
|
||||
postgrest-check postgrest-watch
|
||||
postgrest-clean postgrest-with-all
|
||||
postgrest-coverage postgrest-with-postgresql-10
|
||||
postgrest-lint postgrest-with-postgresql-11
|
||||
postgrest-run postgrest-with-postgresql-12
|
||||
postgrest-style postgrest-with-postgresql-13
|
||||
postgrest-style-check postgrest-with-postgresql-9.6
|
||||
postgrest-test-io
|
||||
postgrest-test-memory
|
||||
$ nix-shell --arg docker true
|
||||
[nix-shell]$ postgrest-docker-<tab>
|
||||
postgrest-docker-load
|
||||
...
|
||||
|
||||
```
|
||||
|
||||
Note that `postgrest-test-memory` is now also available.
|
||||
Note that `postgrest-docker-load` is now also available.
|
||||
|
||||
To run one-off commands, you can also use `nix-shell --run <command>`, which
|
||||
will launch the Nix shell, run that one command and exit. Note that the tab
|
||||
@@ -166,7 +174,7 @@ $ nix-shell --run "postgrest-with-all postgrest-test-spec"
|
||||
|
||||
# Run the tests against a specific version of PostgreSQL (use tab-completion in
|
||||
# nix-shell to see all available versions):
|
||||
$ nix-shell --run "postgrest-with-postgresql-13 postgrest-test-spec"
|
||||
$ nix-shell --run "postgrest-with-pg-13 postgrest-test-spec"
|
||||
|
||||
```
|
||||
|
||||
@@ -276,7 +284,7 @@ Tools like `postgrest-build`, `postgrest-run`, `postgrest-repl` etc. are simple
|
||||
also run in CI, with the exception of the IO and Memory checks that need to be run
|
||||
separately.
|
||||
|
||||
`postgrest-with-postgresql-*` take a command as an argument and will run it
|
||||
`postgrest-with-pg-*` take a command as an argument and will run it
|
||||
with a temporary database. `postgrest-with-all` will run the command against
|
||||
all supported PostgreSQL versions. Tests run without `postgrest-with-*` are
|
||||
run against the latest PostgreSQL version by default.
|
||||
@@ -371,10 +379,8 @@ that).
|
||||
|
||||
We also use `default.nix` to load our pinned version of the `nixpkgs`
|
||||
repository. This set of packages will always be the same, independently from
|
||||
where or when you use it. The pinned version can be upgraded with the small
|
||||
`nixpkgs-upgrade` utility. Running `nixpkgs-upgrade > nix/nixpkgs-version.nix`
|
||||
in `nix-shell` will upgrade the pinned version to the latest `nixpkgs-unstable`
|
||||
version.
|
||||
where or when you use it. The pinned version is taken from `flake.lock` and
|
||||
can be updated with `postgrest-nixpkgs-upgrade`.
|
||||
|
||||
### `shell.nix`
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
{ buildPythonPackage
|
||||
, fetchFromGitHub
|
||||
, lib
|
||||
, nose
|
||||
, sphinx
|
||||
, sphinx-rtd-theme
|
||||
}:
|
||||
|
||||
buildPythonPackage rec {
|
||||
pname = "sphinx-rtd-dark-mode";
|
||||
version = "1.3.0";
|
||||
format = "setuptools";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "MrDogeBro";
|
||||
repo = "sphinx_rtd_dark_mode";
|
||||
rev = "refs/tags/v${version}";
|
||||
hash = "sha256-N5KG2Wqn9wfGNY3VH4FnBce1aZUbnvVmwD10Loe0Qn4=";
|
||||
};
|
||||
|
||||
propagatedBuildInputs = [
|
||||
sphinx-rtd-theme
|
||||
];
|
||||
|
||||
nativeCheckInputs = [
|
||||
nose
|
||||
sphinx
|
||||
];
|
||||
|
||||
checkPhase = ''
|
||||
runHook preCheck
|
||||
nosetests tests
|
||||
runHook postCheck
|
||||
'';
|
||||
|
||||
pythonImportsCheck = [
|
||||
"sphinx_rtd_dark_mode"
|
||||
];
|
||||
|
||||
meta = with lib; {
|
||||
description = "Adds a toggleable dark mode to the Read the Docs theme for Sphinx.";
|
||||
homepage = "https://github.com/MrDogeBro/sphinx_rtd_dark_mode";
|
||||
changelog = "https://github.com/MrDogeBro/sphinx_rtd_dark_mode/releases/tag/v${version}";
|
||||
license = licenses.mit;
|
||||
};
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
# Creating a separate libpq package is is discussed in
|
||||
# https://github.com/NixOS/nixpkgs/issues/61580, but nixpkgs has not moved
|
||||
# forward, yet.
|
||||
# This package is passed to postgresql-libpq (haskell) which needs to be
|
||||
# cross-compiled to the static build and possibly other architectures as
|
||||
# as well. To reduce the number of dependencies that need to be built with
|
||||
# it, this derivation focuses on building the client libraries only. No
|
||||
# server, no tests.
|
||||
{ stdenv
|
||||
, lib
|
||||
, openssl
|
||||
, zlib
|
||||
, postgresql
|
||||
, pkg-config
|
||||
, tzdata
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
pname = "libpq";
|
||||
inherit (postgresql) src version patches;
|
||||
|
||||
configureFlags = [
|
||||
"--without-gssapi"
|
||||
"--without-icu"
|
||||
"--without-readline"
|
||||
"--with-openssl"
|
||||
"--with-system-tzdata=${tzdata}/share/zoneinfo"
|
||||
"--sysconfdir=/etc/postgresql"
|
||||
];
|
||||
|
||||
nativeBuildInputs = [ pkg-config tzdata ];
|
||||
buildInputs = [ openssl zlib ];
|
||||
|
||||
buildFlags = [ "submake-libpq" "submake-libpgport" ];
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
make -C src/bin/pg_config install
|
||||
make -C src/common install
|
||||
make -C src/include install
|
||||
make -C src/interfaces/libpq install
|
||||
make -C src/port install
|
||||
|
||||
rm -rfv $out/share
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
outputs = [ "out" ];
|
||||
|
||||
meta = with lib; {
|
||||
homepage = "https://www.postgresql.org";
|
||||
description = "Client API library for PostgreSQL";
|
||||
license = licenses.postgresql;
|
||||
};
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
# Pinned version of Nixpkgs, generated with postgrest-nixpkgs-upgrade.
|
||||
{
|
||||
owner = "NixOS";
|
||||
repo = "nixpkgs";
|
||||
date = "2024-04-20";
|
||||
rev = "92d295f588631b0db2da509f381b4fb1e74173c5";
|
||||
tarballHash = "162w28y4i5c8g5qhjvs827qxphf2a8n4c8fwhcywzl1j1a35h2im";
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
, coreutils
|
||||
, git
|
||||
, lib
|
||||
, moreutils
|
||||
, runCommand
|
||||
, shellcheck
|
||||
, stdenv
|
||||
@@ -56,7 +57,7 @@ let
|
||||
# Example: This way `postgrest-watch -h` will return the help output for watch, while
|
||||
# `postgrest-watch postgrest-test-spec -h` will return the help output for test-spec.
|
||||
# Taken from: https://github.com/matejak/argbash/issues/114#issuecomment-557108274
|
||||
sed '/_positionals_count + 1/a\\t\t\t\tset -- "''${@:1:1}" "--" "''${@:2}"' -i $out
|
||||
sed '/_positionals_count + 1/a\\t\t\t\tset -- "''${@:1:1}" "--" "''${@:2}"' $out | ${moreutils}/bin/sponge $out
|
||||
'';
|
||||
|
||||
bash-completion =
|
||||
@@ -66,7 +67,7 @@ let
|
||||
''
|
||||
|
||||
+ lib.optionalString (positionalCompletion != "") ''
|
||||
sed 's#COMPREPLY.*compgen -o bashdefault .*$#${escape positionalCompletion}#' -i $out
|
||||
sed 's#COMPREPLY.*compgen -o bashdefault .*$#${escape positionalCompletion}#' $out | ${moreutils}/bin/sponge $out
|
||||
''
|
||||
);
|
||||
|
||||
@@ -103,8 +104,7 @@ let
|
||||
''
|
||||
|
||||
+ lib.optionalString withTmpDir ''
|
||||
mkdir -p "''${TMPDIR:-/tmp}/postgrest"
|
||||
tmpdir="$(${coreutils}/bin/mktemp -d --tmpdir postgrest/${name}-XXX)"
|
||||
tmpdir="$(${coreutils}/bin/mktemp -d --tmpdir ${name}-XXX)"
|
||||
|
||||
# we keep the tmpdir when an error occurs for debugging
|
||||
trap 'echo Temporary directory kept at: $tmpdir' ERR
|
||||
|
||||
@@ -3,9 +3,5 @@
|
||||
checked-shell-script = import ./checked-shell-script;
|
||||
gitignore = import ./gitignore.nix;
|
||||
haskell-packages = import ./haskell-packages.nix;
|
||||
postgis = import ./postgis.nix;
|
||||
postgresql-libpq = import ./postgresql-libpq.nix;
|
||||
postgresql-legacy = import ./postgresql-legacy.nix;
|
||||
postgresql-future = import ./postgresql-future.nix;
|
||||
slocat = import ./slocat.nix;
|
||||
}
|
||||
|
||||