Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
hfhbd authored Mar 3, 2024
2 parents b04e7de + 2229b7c commit 3a10aeb
Show file tree
Hide file tree
Showing 21 changed files with 337 additions and 100 deletions.
4 changes: 4 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM mcr.microsoft.com/devcontainers/java:21

RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends libpq-dev
12 changes: 12 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
"features": {
"ghcr.io/devcontainers/features/sshd:1": {}
},

"forwardPorts": [
5432
]
}
38 changes: 38 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
version: '3.8'

services:
app:
container_name: javadev
# https://youtrack.jetbrains.com/issue/KT-36871/Support-Aarch64-Linux-as-a-host-for-the-Kotlin-Native
platform: "linux/amd64"
build:
context: .
dockerfile: Dockerfile
environment:
POSTGRES_HOSTNAME: postgresdb
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password

volumes:
- ../..:/workspaces:cached

command: sleep infinity

network_mode: service:db

db:
container_name: postgresdb
image: postgres:latest
restart: unless-stopped
healthcheck:
test: [ "CMD-SHELL", "pg_isready" ]
interval: 1s
timeout: 5s
retries: 10
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
138 changes: 138 additions & 0 deletions .github/actions/action-setup-postgres/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
name: Setup PostgreSQL for Linux/macOS/Windows
author: Ihor Kalnytskyi
description: Setup a preinstalled PostgreSQL server.
branding:
icon: database
color: purple
inputs:
username:
description: The username of the user to setup.
default: postgres
required: false
password:
description: The password of the user to setup.
default: postgres
required: false
database:
description: The database name to setup and grant permissions to created user.
default: postgres
required: false
port:
description: The server port to listen on.
default: "5432"
required: false
outputs:
connection-uri:
description: The connection URI to connect to PostgreSQL.
value: ${{ steps.set-outputs.outputs.connection-uri }}
service-name:
description: The service name with connection parameters.
value: ${{ steps.set-outputs.outputs.service-name }}
runs:
using: composite
steps:
- name: Prerequisites
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
echo "$(pg_config --bindir)" >> $GITHUB_PATH
elif [ "$RUNNER_OS" == "Windows" ]; then
echo "$PGBIN" >> $GITHUB_PATH
echo "PQ_LIB_DIR=$PGROOT\lib" >> $GITHUB_ENV
# The Windows runner has some PostgreSQL environment variables set
# that may confuse users since they may be irrelevant to the
# PostgreSQL server we're using.
for name in "PGROOT" "PGDATA" "PGBIN" "PGUSER" "PGPASSWORD"; do
echo "$name=" >> $GITHUB_ENV
done
elif [ "$RUNNER_OS" == "macOS" ]; then
case "$(sw_vers -productVersion)" in
12.*|13.*)
brew install postgresql@14
echo "/usr/local/opt/postgresql@14/bin" >> $GITHUB_PATH
;;
14.*)
brew install postgresql@16
echo "/opt/homebrew/opt/postgresql@16/bin" >> $GITHUB_PATH
;;
esac
fi
shell: bash

- name: Setup and start PostgreSQL
run: |
export PGDATA="$RUNNER_TEMP/pgdata"
export PWFILE="$RUNNER_TEMP/pwfile"
# Unfortunately 'initdb' could only receive a password via file on disk
# or prompt to enter on. Prompting is not an option since we're running
# in non-interactive mode.
echo '${{ inputs.password }}' > $PWFILE
# There are couple of reasons why we need to create a new PostgreSQL
# database cluster. First and foremost, we have to create a superuser
# with provided credentials. Second, we want the PostgreSQL client
# applications [1] to be available for execution without
# run-from-another-user dances. Third, we want to make sure that
# settings are the same between operating systems and aren't changed by
# package vendors.
#
# [1] https://www.postgresql.org/docs/15/reference-client.html
initdb \
--username="${{ inputs.username }}" \
--pwfile="$PWFILE" \
--auth="scram-sha-256" \
--encoding="UTF-8" \
--locale="en_US.UTF-8" \
--no-instructions
# Do not create unix sockets since they are created by default in the
# directory we have no permissions to (owned by system postgres user).
echo "unix_socket_directories = ''" >> "$PGDATA/postgresql.conf"
echo "port = ${{ inputs.port }}" >> "$PGDATA/postgresql.conf"
pg_ctl start
# Save required connection parameters for created superuser to the
# connection service file [1]. This allows using these connection
# parameters by setting 'PGSERVICE' environment variable or by
# requesting them via connection string.
#
# HOST is required for Linux/macOS because these OS-es default to unix
# sockets but we turned them off.
#
# PORT, USER, PASSWORD and DBNAME are required because they could be
# parametrized via action input parameters.
#
# [1] https://www.postgresql.org/docs/15/libpq-pgservice.html
cat <<EOF > "$PGDATA/pg_service.conf"
[${{ inputs.username }}]
host=localhost
port=${{ inputs.port }}
user=${{ inputs.username }}
password=${{ inputs.password }}
dbname=${{ inputs.database }}
EOF
echo "PGSERVICEFILE=$PGDATA/pg_service.conf" >> $GITHUB_ENV
shell: bash

- name: Setup PostgreSQL database
run: |
# The 'postgres' database is a pre-created database meant for use by
# users, utilities and third party applications. There's no way to
# parametrize the name, so all we can do is to avoid creating a
# database if provided name is 'postgres'.
if [ "${{ inputs.database }}" != "postgres" ]; then
createdb -O "${{ inputs.username }}" "${{ inputs.database }}"
fi
env:
PGSERVICE: ${{ inputs.username }}
shell: bash

- name: Set action outputs
run: |
CONNECTION_URI="postgresql://${{ inputs.username }}:${{ inputs.password }}@localhost:${{ inputs.port }}/${{ inputs.database }}"
echo "connection-uri=$CONNECTION_URI" >> $GITHUB_OUTPUT
echo "service-name=${{ inputs.username }}" >> $GITHUB_OUTPUT
shell: bash
id: set-outputs
12 changes: 12 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,15 @@ updates:
assignees:
- "hfhbd"
rebase-strategy: "disabled"
- package-ecosystem: "devcontainers"
directory: "/"
schedule:
interval: "daily"
assignees:
- "hfhbd"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "daily"
assignees:
- "hfhbd"
8 changes: 4 additions & 4 deletions .github/workflows/CD.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:

jobs:
build:
runs-on: macos-latest
runs-on: macos-14

steps:
- name: Set environment for version
Expand All @@ -18,10 +18,10 @@ jobs:
with:
distribution: 'adopt'
java-version: 17
- uses: gradle/gradle-build-action@v2
- uses: gradle/actions/setup-gradle@v3
- run: brew install libpq
- name: Build with Gradle
run: ./gradlew assemble
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: true
- name: Publish
run: ./gradlew -Pversion=$version -Dorg.gradle.parallel=false --no-configuration-cache publish closeAndReleaseStagingRepository
env:
Expand Down
14 changes: 8 additions & 6 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,25 @@ jobs:
contents: write
strategy:
matrix:
os: [ 'ubuntu-latest', 'macos-latest' ]
os: [ 'ubuntu-latest', 'macos-14', 'macos-latest' ]

env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: true

steps:
- uses: actions/checkout@v4
- uses: Homebrew/actions/setup-homebrew@master
id: set-up-homebrew
- run: brew install libpq
- uses: ./.github/actions/action-setup-postgres
with:
password: password
- uses: actions/setup-java@v4
with:
distribution: 'adopt'
java-version: 17
- uses: gradle/gradle-build-action@v2
- uses: gradle/actions/setup-gradle@v3
with:
dependency-graph: generate-and-submit
gradle-home-cache-cleanup: true
- run: ./gradlew assemble
- uses: ikalnytskyi/action-setup-postgres@v5
with:
password: password
- run: ./gradlew build
2 changes: 1 addition & 1 deletion .github/workflows/Docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
with:
distribution: 'adopt'
java-version: 17
- uses: gradle/gradle-build-action@v2
- uses: gradle/actions/setup-gradle@v3
- name: Generate Docs
run: ./gradlew :dokkaHtmlMultiModule
- uses: actions/upload-pages-artifact@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/gradleWrapper.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ jobs:

steps:
- uses: actions/checkout@v4
- uses: gradle/wrapper-validation-action@v1
- uses: gradle/wrapper-validation-action@v2
39 changes: 28 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# Module postgres-native-sqldelight-driver
# PostgreSQL native SQLDelight driver

A native Postgres driver using libpq.

You can use the driver with [SQLDelight](https://github.com/cashapp/sqldelight), but this is not required.

- [Source code](https://github.com/hfhbd/postgres-native-sqldelight)

> Keep in mind, until now, this is only a single-threaded wrapper over libpq using 1 connection only. There is no connection pool nor multithread support (like JDBC or R2DBC).
> Keep in mind, until now, this is only a single-threaded wrapper over libpq using 1 connection only. There is no
> connection pool nor multithread support (like JDBC or R2DBC).
## Install

Expand Down Expand Up @@ -51,7 +52,8 @@ val driver = PostgresNativeDriver(

This driver supports local and remote listeners.
Local listeners only notify this client, ideally for testing or using the database with only one client at a time.
Remote listener support uses `NOTIFY` and `LISTEN`, so you can use this to sync multiple clients or with existing database
Remote listener support uses `NOTIFY` and `LISTEN`, so you can use this to sync multiple clients or with existing
database
triggers.
SQLDelight uses and expects the table name as payload, but you can provide a mapper function.

Expand All @@ -68,7 +70,8 @@ The identifier is used to reuse prepared statements.
driver.execute(identifier = null, sql = "INSERT INTO foo VALUES (42)", parameters = 0, binders = null)
```

It also supports a real lazy cursor by using a `Flow`. The `fetchSize` parameter defines how many rows are fetched at once:
It also supports a real lazy cursor by using a `Flow`. The `fetchSize` parameter defines how many rows are fetched at
once:

```kotlin
val namesFlow: Flow<Simple> = driver.executeQueryAsFlow(
Expand Down Expand Up @@ -100,26 +103,40 @@ Apache 2

## Contributing

You need libpq installed: https://formulae.brew.sh/formula/libpq#default
### Devcontainers

You have to add the compiler flags to the [libpq.def](postgres-native-sqldelight-driver/src/nativeInterop/cinterop/libpq.def).
The exact flags depend on your config, but you will get them during installing libpq with homebrew.
Start the devcontainer, that's it.

### Local

#### docker compose

This is the preferred local option. The `app` service contains the JVM as well as libpq.

#### Manual

You need to install `libpq`, eg using Homebrew: https://formulae.brew.sh/formula/libpq#default

For installation using homebrew, the default path is already added.

Otherwise, you have to add the compiler flags to
the [libpq.def](postgres-native-sqldelight-driver/src/nativeInterop/cinterop/libpq.def).
The exact flags depend on your config, for example:

```
For compilers to find libpq you may need to set:
export LDFLAGS="-L/home/linuxbrew/.linuxbrew/opt/libpq/lib"
export CPPFLAGS="-I/home/linuxbrew/.linuxbrew/opt/libpq/include"
```

For installation using homebrew, the default path is already added.
##### Testing

### Testing

If you install libpq with homebrew, it will install the platform-specific artifact.
If you installed libpq with homebrew, it will install the platform-specific artifact.

To test other platforms, eg. linux x64 on macOS, you need to install the platform-specific libpq of linux x64 too.

To start the postgres instance, you can use docker:

```sh
docker run -e POSTGRES_PASSWORD=password -p 5432:5432 postgres
```
4 changes: 4 additions & 0 deletions gradle/build-logic/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ dependencyResolutionManagement {
}
}

plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}

rootProject.name = "build-logic"
Loading

0 comments on commit 3a10aeb

Please sign in to comment.