Rename the project from peo to boltage
The name peo cannot be registered on PyPI. Rename the package, the command, the PEO_* environment variables (now BOLTAGE_*), the container paths and scripts, and the source URLs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5418473158
commit
5784de249d
20 files changed
+180
-180
No files matched your search
@@ -1,16 +1,16 @@
|
||||
# peo
|
||||
# boltage
|
||||
|
||||
[neo4j-browser](https://github.com/neo4j/neo4j-browser), cypher-shell and the Neo4j
|
||||
drivers on top of PostgreSQL, using [Apache AGE](https://github.com/apache/age) as the
|
||||
graph engine.
|
||||
|
||||
peo is a small Python server that speaks Neo4j's Bolt protocol and translates Cypher
|
||||
boltage is a small Python server that speaks Neo4j's Bolt protocol and translates Cypher
|
||||
into AGE `cypher()` calls. It can also serve neo4j-browser. A [container
|
||||
image](#container-images) bundles everything, together with
|
||||
[pgAdmin](https://www.pgadmin.org/) for working with the same data in SQL.
|
||||
|
||||
```
|
||||
neo4j-browser (static files) peo (Python) PostgreSQL + AGE
|
||||
neo4j-browser (static files) boltage (Python) PostgreSQL + AGE
|
||||
┌──────────────────────┐ Bolt ┌────────────────────────-──┐ SQL ┌────────────────┐
|
||||
│ in your web browser │───────▶│ Bolt server (TCP + WS) │──────▶│ cypher('g',$$ │
|
||||
│ served on :7474 │ :7687 │ Cypher → AGE translation │ :5432 │ ... $$) │
|
||||
@@ -20,63 +20,63 @@ image](#container-images) bundles everything, together with
|
||||
|
||||
## Installation
|
||||
|
||||
peo needs Python 3.11 or later and a PostgreSQL server with the AGE extension installed
|
||||
boltage needs Python 3.11 or later and a PostgreSQL server with the AGE extension installed
|
||||
and loaded (`shared_preload_libraries=age`).
|
||||
|
||||
```sh
|
||||
pip install 'peo[binary]'
|
||||
PEO_PG_HOST=localhost PEO_PG_DATABASE=postgres peo
|
||||
pip install 'boltage[binary]'
|
||||
BOLTAGE_PG_HOST=localhost BOLTAGE_PG_DATABASE=postgres boltage
|
||||
```
|
||||
|
||||
The `binary` extra pulls in psycopg's prebuilt wheels; leave it out to use a psycopg
|
||||
built against your system's libpq. `python -m peo` works the same as `peo`.
|
||||
built against your system's libpq. `python -m boltage` works the same as `boltage`.
|
||||
|
||||
Neo4j clients can now connect to `neo4j://localhost:7687` with a PostgreSQL user name
|
||||
and password.
|
||||
|
||||
peo does not include neo4j-browser itself. To serve it, install the `browser` extra
|
||||
boltage does not include neo4j-browser itself. To serve it, install the `browser` extra
|
||||
([Starlette](https://www.starlette.io/) and [uvicorn](https://www.uvicorn.org/)),
|
||||
build neo4j-browser and point `PEO_BROWSER_DIR` at its `dist` directory; it is then
|
||||
build neo4j-browser and point `BOLTAGE_BROWSER_DIR` at its `dist` directory; it is then
|
||||
served on <http://localhost:7474/>. The [container images](#container-images) do all of
|
||||
this for you.
|
||||
|
||||
```sh
|
||||
pip install 'peo[binary,browser]'
|
||||
PEO_PG_HOST=localhost PEO_PG_DATABASE=postgres PEO_BROWSER_DIR=/path/to/neo4j-browser/dist peo
|
||||
pip install 'boltage[binary,browser]'
|
||||
BOLTAGE_PG_HOST=localhost BOLTAGE_PG_DATABASE=postgres BOLTAGE_BROWSER_DIR=/path/to/neo4j-browser/dist boltage
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
peo is configured through environment variables:
|
||||
boltage is configured through environment variables:
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `PEO_PG_HOST` | `127.0.0.1` | PostgreSQL host. |
|
||||
| `PEO_PG_PORT` | `5432` | PostgreSQL port. |
|
||||
| `PEO_PG_DATABASE` | `$POSTGRES_DB`, else `$POSTGRES_USER`, else `postgres` | PostgreSQL database holding the graphs. |
|
||||
| `PEO_DEFAULT_GRAPH` | `neo4j` | Graph used when a client does not pick a database. |
|
||||
| `PEO_BOLT_PORT` | `7687` | Port the Bolt server listens on (TCP and WebSocket). |
|
||||
| `PEO_HTTP_PORT` | `7474` | Port neo4j-browser is served on, when `PEO_BROWSER_DIR` is set. |
|
||||
| `PEO_BROWSER_DIR` | (unset) | neo4j-browser `dist` directory to serve; needs the `browser` extra. |
|
||||
| `PEO_ADVERTISED_BOLT_PORT` | `$PEO_BOLT_PORT` | Bolt port advertised to the browser; set it when clients reach the Bolt port on another port. |
|
||||
| `PEO_ADVERTISED_HOST` | `localhost` | Host reported in `SHOW DATABASES` and to clients that do not send a routing address. |
|
||||
| `PEO_LOG_LEVEL` | `INFO` | `DEBUG` logs every generated SQL statement. |
|
||||
| `BOLTAGE_PG_HOST` | `127.0.0.1` | PostgreSQL host. |
|
||||
| `BOLTAGE_PG_PORT` | `5432` | PostgreSQL port. |
|
||||
| `BOLTAGE_PG_DATABASE` | `$POSTGRES_DB`, else `$POSTGRES_USER`, else `postgres` | PostgreSQL database holding the graphs. |
|
||||
| `BOLTAGE_DEFAULT_GRAPH` | `neo4j` | Graph used when a client does not pick a database. |
|
||||
| `BOLTAGE_BOLT_PORT` | `7687` | Port the Bolt server listens on (TCP and WebSocket). |
|
||||
| `BOLTAGE_HTTP_PORT` | `7474` | Port neo4j-browser is served on, when `BOLTAGE_BROWSER_DIR` is set. |
|
||||
| `BOLTAGE_BROWSER_DIR` | (unset) | neo4j-browser `dist` directory to serve; needs the `browser` extra. |
|
||||
| `BOLTAGE_ADVERTISED_BOLT_PORT` | `$BOLTAGE_BOLT_PORT` | Bolt port advertised to the browser; set it when clients reach the Bolt port on another port. |
|
||||
| `BOLTAGE_ADVERTISED_HOST` | `localhost` | Host reported in `SHOW DATABASES` and to clients that do not send a routing address. |
|
||||
| `BOLTAGE_LOG_LEVEL` | `INFO` | `DEBUG` logs every generated SQL statement. |
|
||||
|
||||
## How it works
|
||||
|
||||
- **Databases are AGE graphs.** Every AGE graph shows up as a Neo4j database, and
|
||||
`:use <name>` switches between them. Clients that do not pick a database get `PEO_DEFAULT_GRAPH`
|
||||
`:use <name>` switches between them. Clients that do not pick a database get `BOLTAGE_DEFAULT_GRAPH`
|
||||
(`neo4j`); the full container image and the compose setup create that graph on first start. `CREATE DATABASE x` and `DROP DATABASE x` on the `system`
|
||||
database call `create_graph` / `drop_graph`; AGE requires names of at least 3 characters.
|
||||
- **Queries** are sent to AGE as `SELECT * FROM cypher('<graph>', $$ <query> $$) AS (...)`.
|
||||
peo works out the result columns from the final `RETURN` clause and inlines
|
||||
boltage works out the result columns from the final `RETURN` clause and inlines
|
||||
query parameters as Cypher literals.
|
||||
- **Neo4j procedures** that neo4j-browser relies on (`dbms.components`, `SHOW DATABASES`,
|
||||
`db.labels`, `db.schema.visualization`, `SHOW PROCEDURES`, ...) are emulated from the
|
||||
AGE catalog.
|
||||
- **Workarounds for AGE**: neo4j-browser's "expand node" query uses a pattern
|
||||
comprehension, and its relationship lookup uses `id(n) IN [...]`, which AGE rejects
|
||||
for lists of more than one element. peo rewrites both into equivalent Cypher
|
||||
for lists of more than one element. boltage rewrites both into equivalent Cypher
|
||||
that AGE accepts.
|
||||
- **Authentication** is passed straight through: every Bolt connection opens its own
|
||||
PostgreSQL connection with the credentials you log in with.
|
||||
@@ -283,7 +283,7 @@ things to keep in mind:
|
||||
- This only works in one direction. AGE writes label tables without firing triggers, so
|
||||
a Cypher `CREATE`, `SET` or `DELETE` on a mirrored label does not reach the tables,
|
||||
and the next change to the row overwrites it. AGE does check table privileges, so
|
||||
grant the users that log in through peo only `SELECT` on the mirrored label tables.
|
||||
grant the users that log in through boltage only `SELECT` on the mirrored label tables.
|
||||
The triggers are `SECURITY DEFINER`, so relational writes still reach the graph.
|
||||
Superusers bypass privileges.
|
||||
- Vertex ids need a `bigint` primary key below 2<sup>48</sup>. Other keys, such as
|
||||
@@ -295,23 +295,23 @@ things to keep in mind:
|
||||
|
||||
The [`Containerfile`](Containerfile) builds two images:
|
||||
|
||||
- **full** (the default): PostgreSQL with AGE, peo, neo4j-browser and pgAdmin in one
|
||||
- **full** (the default): PostgreSQL with AGE, boltage, neo4j-browser and pgAdmin in one
|
||||
container.
|
||||
- **slim** (`--target slim`): only peo and neo4j-browser, for a PostgreSQL server
|
||||
- **slim** (`--target slim`): only boltage and neo4j-browser, for a PostgreSQL server
|
||||
with AGE that runs elsewhere. [`compose.yaml`](compose.yaml) runs it next to
|
||||
separate PostgreSQL and pgAdmin containers.
|
||||
|
||||
Any OCI-compatible build tool works. Docker does not pick up a `Containerfile` by
|
||||
itself, so pass it explicitly: `docker build -f Containerfile -t peo .`. `docker`
|
||||
itself, so pass it explicitly: `docker build -f Containerfile -t boltage .`. `docker`
|
||||
takes the same options as `podman` in the commands below.
|
||||
|
||||
### Everything in one container
|
||||
|
||||
```sh
|
||||
podman build -t peo .
|
||||
podman run -d --name peo -e POSTGRES_PASSWORD=secret \
|
||||
podman build -t boltage .
|
||||
podman run -d --name boltage -e POSTGRES_PASSWORD=secret \
|
||||
-p 7474:7474 -p 7687:7687 -p 5050:5050 -p 5432:5432 \
|
||||
-v peo-data:/var/lib/postgresql -v peo-pgadmin:/var/lib/pgadmin peo
|
||||
-v boltage-data:/var/lib/postgresql -v boltage-pgadmin:/var/lib/pgadmin boltage
|
||||
```
|
||||
|
||||
| Port | Service | Log in with |
|
||||
@@ -321,41 +321,41 @@ podman run -d --name peo -e POSTGRES_PASSWORD=secret \
|
||||
| 5050 | pgAdmin: <http://localhost:5050/> | `admin@example.com` and `POSTGRES_PASSWORD` |
|
||||
| 5432 | PostgreSQL, for `psql` and other SQL clients | same as neo4j-browser |
|
||||
|
||||
pgAdmin comes with the bundled PostgreSQL server already registered as "peo";
|
||||
pgAdmin comes with the bundled PostgreSQL server already registered as "boltage";
|
||||
it asks for the PostgreSQL password the first time you open it. AGE stores each
|
||||
graph as a schema of the same name, with one table per label.
|
||||
|
||||
Besides peo's own variables above, the image uses these:
|
||||
Besides boltage's own variables above, the image uses these:
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `POSTGRES_PASSWORD` | (required) | Password of the PostgreSQL superuser, see the [postgres image docs](https://hub.docker.com/_/postgres). `POSTGRES_USER` and `POSTGRES_DB` work too. |
|
||||
| `PEO_DEFAULT_GRAPH` | `neo4j` | Also the graph created when the database is initialised. |
|
||||
| `BOLTAGE_DEFAULT_GRAPH` | `neo4j` | Also the graph created when the database is initialised. |
|
||||
| `PGADMIN_DEFAULT_EMAIL` | `admin@example.com` | pgAdmin login, created on first start. |
|
||||
| `PGADMIN_DEFAULT_PASSWORD` | `$POSTGRES_PASSWORD` | pgAdmin login password, set on first start. |
|
||||
| `PEO_PGADMIN` | `true` | Set to `false` to not start pgAdmin. |
|
||||
| `PEO_PGADMIN_PORT` | `5050` | Port pgAdmin listens on inside the container. |
|
||||
| `BOLTAGE_PGADMIN` | `true` | Set to `false` to not start pgAdmin. |
|
||||
| `BOLTAGE_PGADMIN_PORT` | `5050` | Port pgAdmin listens on inside the container. |
|
||||
|
||||
pgAdmin keeps its users and settings in `/var/lib/pgadmin`; changing
|
||||
`PGADMIN_DEFAULT_*` after the first start has no effect unless that directory is empty.
|
||||
|
||||
### peo with a separate PostgreSQL server
|
||||
### boltage with a separate PostgreSQL server
|
||||
|
||||
The slim image runs peo and serves neo4j-browser, and is configured with the
|
||||
The slim image runs boltage and serves neo4j-browser, and is configured with the
|
||||
variables in [Configuration](#configuration). Point it at any PostgreSQL server
|
||||
that has AGE installed and loaded (`shared_preload_libraries=age`):
|
||||
|
||||
```sh
|
||||
podman build --target slim -t peo:slim .
|
||||
podman run -d --name peo -p 7474:7474 -p 7687:7687 \
|
||||
-e PEO_PG_HOST=db.example.com -e PEO_PG_DATABASE=graphs peo:slim
|
||||
podman build --target slim -t boltage:slim .
|
||||
podman run -d --name boltage -p 7474:7474 -p 7687:7687 \
|
||||
-e BOLTAGE_PG_HOST=db.example.com -e BOLTAGE_PG_DATABASE=graphs boltage:slim
|
||||
```
|
||||
|
||||
peo creates no graphs of its own. If the database has none yet, run
|
||||
boltage creates no graphs of its own. If the database has none yet, run
|
||||
`CREATE DATABASE neo4j` on the `system` database (`:use system` in neo4j-browser),
|
||||
or `SELECT ag_catalog.create_graph('neo4j');` in SQL.
|
||||
|
||||
### Compose: peo, PostgreSQL and pgAdmin as separate containers
|
||||
### Compose: boltage, PostgreSQL and pgAdmin as separate containers
|
||||
|
||||
[`compose.yaml`](compose.yaml) builds the slim image and runs it with
|
||||
[`apache/age`](https://hub.docker.com/r/apache/age) for PostgreSQL and the official
|
||||
@@ -368,10 +368,10 @@ podman compose up -d
|
||||
|
||||
It works with `podman compose` and `docker compose`, and publishes the same ports and
|
||||
logins as the full image: neo4j-browser on 7474, Bolt on 7687, pgAdmin on 5050 and
|
||||
PostgreSQL on 5432. Set `PEO_POSTGRES_PORT` to publish PostgreSQL on another host
|
||||
port. The default graph (`PEO_DEFAULT_GRAPH`, `neo4j`) is created when the database
|
||||
is initialised, and pgAdmin comes with the server already registered as "peo".
|
||||
`PGADMIN_DEFAULT_EMAIL`, `PGADMIN_DEFAULT_PASSWORD` and `PEO_LOG_LEVEL` can be set
|
||||
PostgreSQL on 5432. Set `BOLTAGE_POSTGRES_PORT` to publish PostgreSQL on another host
|
||||
port. The default graph (`BOLTAGE_DEFAULT_GRAPH`, `neo4j`) is created when the database
|
||||
is initialised, and pgAdmin comes with the server already registered as "boltage".
|
||||
`PGADMIN_DEFAULT_EMAIL`, `PGADMIN_DEFAULT_PASSWORD` and `BOLTAGE_LOG_LEVEL` can be set
|
||||
in `.env` too. Data is kept in the `postgres-data` and `pgadmin-data` volumes;
|
||||
`podman compose down -v` removes them.
|
||||
|
||||
@@ -394,11 +394,11 @@ This is a first version. Things that do not work (yet):
|
||||
- User and role management, `SHOW TRANSACTIONS`, `:sysinfo`.
|
||||
- TLS (`bolt+s://`, HTTPS).
|
||||
- Each query's full result is fetched from PostgreSQL before it is streamed to the
|
||||
client, so very large results use memory in peo.
|
||||
client, so very large results use memory in boltage.
|
||||
|
||||
## Development
|
||||
|
||||
peo depends on `psycopg` 3 and `websockets`, plus Starlette and uvicorn for the
|
||||
boltage depends on `psycopg` 3 and `websockets`, plus Starlette and uvicorn for the
|
||||
`browser` extra. To work on it, install it in editable mode; `python -m build` (or
|
||||
`uv build`) builds an sdist and wheel:
|
||||
|
||||
@@ -416,12 +416,12 @@ python tests/smoke_test.py neo4j://localhost:7687 postgres secret
|
||||
|
||||
## License
|
||||
|
||||
peo is free software, licensed under the GNU General Public License v3.0 or
|
||||
boltage is free software, licensed under the GNU General Public License v3.0 or
|
||||
later; see [LICENSE](LICENSE). The container images bundle third-party software
|
||||
under their own licenses, including neo4j-browser (GPL-3.0), Apache AGE
|
||||
(Apache-2.0), PostgreSQL and pgAdmin (PostgreSQL License). See
|
||||
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) for the full list and where
|
||||
each license text and source archive is in the image.
|
||||
|
||||
Neo4j is a trademark of Neo4j, Inc.; peo is not affiliated with or endorsed
|
||||
Neo4j is a trademark of Neo4j, Inc.; boltage is not affiliated with or endorsed
|
||||
by Neo4j.
|
||||
Reference in new issue
Block a user