Rename peo4c to peo

Renames the Python package, environment variables (PEO4C_* to PEO_*), the
SQL helper schema, image paths and the entrypoint script.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Bart BroereandClaude Opus 5.5 committed 2026-10-14 15:21:42 +02:00
1 parent 7bd044ddb9
commit fd0dda6470
17 files changed
+124 -124

No files matched your search

+25 -25
View File
@@ -1,4 +1,4 @@
# peo4c
# peo
[neo4j-browser](https://github.com/neo4j/neo4j-browser) running on PostgreSQL, using
[Apache AGE](https://github.com/apache/age) as the graph engine.
@@ -7,7 +7,7 @@ Everything ships in one container image, together with
[pgAdmin](https://www.pgadmin.org/) for working with the same data in SQL:
```
neo4j-browser (static files) peo4c bridge (Python) PostgreSQL + AGE
neo4j-browser (static files) peo bridge (Python) PostgreSQL + AGE
┌──────────────────────┐ Bolt ┌──────────────────────────┐ SQL ┌────────────────┐
│ in your web browser │───────▶│ Bolt server (TCP + WS) │──────▶│ cypher('g',$$ │
│ served on :7474 │ :7687 │ Cypher → AGE translation │ :5432 │ ... $$) │
@@ -18,10 +18,10 @@ Everything ships in one container image, together with
## Quick start
```sh
podman build -t peo4c .
podman run -d --name peo4c -e POSTGRES_PASSWORD=secret \
podman build -t peo .
podman run -d --name peo -e POSTGRES_PASSWORD=secret \
-p 7474:7474 -p 7687:7687 -p 5050:5050 -p 5432:5432 \
-v peo4c-data:/var/lib/postgresql -v peo4c-pgadmin:/var/lib/pgadmin peo4c
-v peo-data:/var/lib/postgresql -v peo-pgadmin:/var/lib/pgadmin peo
```
| Port | Service | Log in with |
@@ -31,7 +31,7 @@ podman run -d --name peo4c -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 "peo4c";
pgAdmin comes with the bundled PostgreSQL server already registered as "peo";
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.
@@ -41,9 +41,9 @@ graph as a schema of the same name, with one table per label.
- **Databases are AGE graphs.** Every AGE graph shows up as a Neo4j database, and
`:use <name>` switches between them. A graph named `neo4j` is created on first start
(`PEO4C_DEFAULT_GRAPH`). `CREATE DATABASE x` and `DROP DATABASE x` on the `system`
(`PEO_DEFAULT_GRAPH`). `CREATE DATABASE x` and `DROP DATABASE x` on the `system`
database call `create_graph` / `drop_graph`; AGE requires names of at least 3 characters,
and `peo4c` is reserved for the schema holding peo4c's SQL helpers.
and `peo` is reserved for the schema holding peo's SQL helpers.
- **Queries** are sent to AGE as `SELECT * FROM cypher('<graph>', $$ <query> $$) AS (...)`.
The bridge works out the result columns from the final `RETURN` clause and inlines
query parameters as Cypher literals.
@@ -60,7 +60,7 @@ graph as a schema of the same name, with one table per label.
## Querying the graph from SQL
AGE stores each node label and relationship type as a table in the graph's schema,
with all properties in one `agtype` column, `properties`. peo4c adds a generated
with all properties in one `agtype` column, `properties`. peo adds a generated
column for every property key it finds, so you can use plain SQL:
```sql
@@ -70,8 +70,8 @@ CREATE INDEX ON neo4j."Person" (name);
AGE's Cypher writes do not fire PostgreSQL triggers, so new keys cannot be caught
the moment they are written. Instead the bridge calls
`CALL peo4c.sync_property_columns()` every few seconds
(`PEO4C_PROPERTY_COLUMNS_INTERVAL`), which you can also run yourself. It only scans
`CALL peo.sync_property_columns()` every few seconds
(`PEO_PROPERTY_COLUMNS_INTERVAL`), which you can also run yourself. It only scans
tables that had inserts or updates since its previous run, and adds all new keys of a
table with a single `ALTER TABLE`. Once a column exists, PostgreSQL keeps it in step
with every `CREATE`, `MERGE`, `SET` and `REMOVE`.
@@ -91,17 +91,17 @@ with every `CREATE`, `MERGE`, `SET` and `REMOVE`.
| 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. |
| `PEO4C_DEFAULT_GRAPH` | `neo4j` | Graph created at initialisation and used when a client does not pick a database. |
| `PEO4C_PG_DATABASE` | `$POSTGRES_DB` | PostgreSQL database holding the graphs. |
| `PEO4C_ADVERTISED_BOLT_PORT` | `7687` | Bolt port advertised to the browser; set it when you publish 7687 on another host port. |
| `PEO4C_ADVERTISED_HOST` | `localhost` | Host reported in `SHOW DATABASES` and to clients that do not send a routing address. |
| `PEO4C_LOG_LEVEL` | `INFO` | `DEBUG` logs every generated SQL statement. |
| `PEO4C_PROPERTY_COLUMNS` | `true` | Set to `false` to stop adding generated property columns. |
| `PEO4C_PROPERTY_COLUMNS_INTERVAL` | `5` | Seconds between checks for new property keys. |
| `PEO_DEFAULT_GRAPH` | `neo4j` | Graph created at initialisation and used when a client does not pick a database. |
| `PEO_PG_DATABASE` | `$POSTGRES_DB` | PostgreSQL database holding the graphs. |
| `PEO_ADVERTISED_BOLT_PORT` | `7687` | Bolt port advertised to the browser; set it when you publish 7687 on another host 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. |
| `PEO_PROPERTY_COLUMNS` | `true` | Set to `false` to stop adding generated property columns. |
| `PEO_PROPERTY_COLUMNS_INTERVAL` | `5` | Seconds between checks for new property keys. |
| `PGADMIN_DEFAULT_EMAIL` | `admin@example.com` | pgAdmin login, created on first start. |
| `PGADMIN_DEFAULT_PASSWORD` | `$POSTGRES_PASSWORD` | pgAdmin login password, set on first start. |
| `PEO4C_PGADMIN` | `true` | Set to `false` to not start pgAdmin. |
| `PEO4C_PGADMIN_PORT` | `5050` | Port pgAdmin listens on inside the container. |
| `PEO_PGADMIN` | `true` | Set to `false` to not start pgAdmin. |
| `PEO_PGADMIN_PORT` | `5050` | Port pgAdmin listens on inside the container. |
Build arguments: `AGE_IMAGE` (base image, default `apache/age:release_PG18_1.8.0`),
`NEO4J_BROWSER_REF` (neo4j-browser commit to build) and `PGADMIN_VERSION` (default `9.18`).
@@ -125,15 +125,15 @@ This is a first version. Things that do not work (yet):
## Development
The bridge is a dependency-light Python package in [`bridge/peo4c`](bridge/peo4c)
The bridge is a dependency-light Python package in [`bridge/peo`](bridge/peo)
(only `psycopg` 3). To run it outside the container against any AGE-enabled
PostgreSQL:
```sh
pip install 'psycopg[binary]'
cd bridge
PEO4C_PG_HOST=localhost PEO4C_PG_DATABASE=postgres PEO4C_BROWSER_DIR=/path/to/neo4j-browser/dist \
python -m peo4c
PEO_PG_HOST=localhost PEO_PG_DATABASE=postgres PEO_BROWSER_DIR=/path/to/neo4j-browser/dist \
python -m peo
```
[`tests/smoke_test.py`](tests/smoke_test.py) runs end-to-end checks through the official
@@ -146,12 +146,12 @@ python tests/smoke_test.py neo4j://localhost:7687 postgres secret
## License
peo4c is free software, licensed under the GNU General Public License v3.0 or
peo is free software, licensed under the GNU General Public License v3.0 or
later; see [LICENSE](LICENSE). The container image bundles third-party software
under its 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.; peo4c is not affiliated with or endorsed
Neo4j is a trademark of Neo4j, Inc.; peo is not affiliated with or endorsed
by Neo4j.