Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
__pycache__/
*.pyc
*.pyo
.git/
.github/
.gitignore
.dockerignore
.env
.env.example
.venv/
executions_tmp/
executions/
.pytest_cache/
.ruff_cache/
__pycache__/
*.pyc
*.pyo
results/
tests/
conftest.py
requirements-dev.txt
pyproject.toml
README.md
CONTRIBUTING.md
SECURITY.md
LICENSE
.dockerignore
Dockerfile
docker-compose.yml
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,9 @@ DB_PORT=5432
DB_USER=user
DB_PASSWORD=password
DB_NAME=test_db

# small (10k) | medium (100k) | large (1M)
DB_SEED_SIZE=medium

# DEBUG | INFO | WARNING | ERROR
LOG_LEVEL=INFO
58 changes: 58 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
test:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:17
env:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: test_db
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 5s
--health-timeout 5s
--health-retries 10

env:
TEST_DB_HOST: localhost
TEST_DB_PORT: 5432
TEST_DB_USER: user
TEST_DB_PASSWORD: password
TEST_DB_NAME: test_db

steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version-file: .python-version
cache: pip

- name: Install dependencies
run: pip install -r requirements.txt -r requirements-dev.txt

- name: Create schema
run: |
# pg_isready answers before the POSTGRES_DB bootstrap finishes, so
# wait on the database itself rather than on the server.
until psql "$DSN" -c 'SELECT 1' >/dev/null 2>&1; do sleep 1; done
psql "$DSN" -f sql/init.sql
env:
DSN: postgresql://user:password@localhost:5432/test_db

- name: Lint
run: ruff check .

- name: Test
run: pytest --cov --cov-report=term-missing
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,11 @@ cython_debug/

# PyPI configuration file
.pypirc

# macOS
.DS_Store

# Tool caches created by the container at runtime
.matplotlib/
.gunicorn/
.ruff_cache/
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
41 changes: 41 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Contributing

## Setup

```bash
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt -r requirements-dev.txt
docker compose up -d db
psql "postgresql://user:password@localhost:5432/test_db" -f sql/init.sql
```

## Before opening a PR

```bash
ruff check .
pytest --cov
```

Both run in CI against a real PostgreSQL service, so integration tests will not be skipped there.

## Adding a benchmark

See [Adding your own benchmark](README.md#adding-your-own-benchmark). The rules that matter:

- **Use `measure()`** from `benchmarks.base` — it does the warm-up and the median. Hand-rolled
`time.perf_counter()` around a single run reintroduces the cold-cache bias.
- **Derive your data points from `table_row_count(conn)`**, never hardcode them. A benchmark whose
parameters exceed the dataset silently measures an empty result set.
- **Prefix any object you create with `sqlperf_`** and drop it in `teardown()`. The tool must never
destroy a table it did not create.
- **Raise `BenchmarkNotApplicable`** when the dataset is too small for your benchmark to mean
anything, instead of returning a chart built on nothing.

Every benchmark is automatically covered by the integration suite, which asserts that it fetches a
non-empty result set. If your benchmark cannot satisfy that, it is measuring the wrong thing.

## Commits

[Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `chore:`, `docs:`,
`test:`. Keep PRs small.
10 changes: 8 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@ RUN pip install --no-cache-dir -r requirements.txt

COPY . .

RUN chown -R appuser:appuser /app
# results/ is a mounted volume; it must exist and be writable before the
# volume inherits its ownership.
RUN mkdir -p /app/results && chown -R appuser:appuser /app

USER appuser

ENV HOME=/tmp \
MPLCONFIGDIR=/tmp/matplotlib \
PYTHONUNBUFFERED=1

EXPOSE 8000

HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/')" || exit 1

CMD ["gunicorn", "--workers", "3", "--bind", "0.0.0.0:8000", "wsgi:app"]
CMD ["gunicorn", "--workers", "3", "--timeout", "300", "--bind", "0.0.0.0:8000", "wsgi:app"]
Loading
Loading