https://github.com/curt/postgis-base58id
PostgreSQL extension providing a native 64-bit `base58id` data type with automatic Base58 encoding. Stores IDs compactly (8 bytes) while displaying as URL-safe 11-character strings. Designed for time-based distributed IDs with full indexing, comparison operators, and efficient binary I/O.
https://github.com/curt/postgis-base58id
Last synced: 29 days ago
JSON representation
PostgreSQL extension providing a native 64-bit `base58id` data type with automatic Base58 encoding. Stores IDs compactly (8 bytes) while displaying as URL-safe 11-character strings. Designed for time-based distributed IDs with full indexing, comparison operators, and efficient binary I/O.
- Host: GitHub
- URL: https://github.com/curt/postgis-base58id
- Owner: curt
- License: mit
- Created: 2025-10-04T16:25:36.000Z (10 months ago)
- Default Branch: dev
- Last Pushed: 2025-10-06T09:30:32.000Z (10 months ago)
- Last Synced: 2025-10-14T20:39:57.012Z (10 months ago)
- Language: C
- Homepage:
- Size: 10.7 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# postgis-base58id
A PostgreSQL extension providing a native **base58id** data type: a 64-bit unsigned integer stored compactly (8 bytes, pass-by-value) with automatic Base58 encoding for text I/O. All values are zero-padded to 11 characters for consistent formatting. Designed for time-based distributed IDs (Snowflake, Sonyflake, etc.) that display as short, URL-safe strings without requiring wide character columns.
## Features
- **Compact storage**: 8 bytes, pass-by-value (same as `bigint`)
- **Base58 encoding**: Bitcoin alphabet (no `0OIl` ambiguity), zero-padded to 11 characters
- **Full operator support**: Comparison operators (`<`, `<=`, `=`, `>=`, `>`, `<>`)
- **Indexable**: B-tree and hash operator classes included
- **Cast support**: Bidirectional casts with `bigint` and `text`
- **Binary I/O**: Efficient `COPY` and client protocol support
- **Uniform hash distribution**: Uses PostgreSQL's `hash_any()` for optimal hash index performance
## Project Structure
```
.
├── extension/
│ ├── base58id.c # C implementation (encoding, I/O, operators)
│ ├── base58id--1.0.sql # SQL type/function definitions
│ ├── base58id.control # Extension metadata
│ └── Makefile # PGXS build (for "make install")
├── docker/
│ └── initdb/
│ └── 01-enable-base58id.sql # Auto-enable extension on container init
├── Dockerfile.ext # Final runtime image (FROM PostGIS base + extension)
├── Makefile # Orchestrates multi-stage build
└── dist/ # Staged extension files (created by "make dist")
```
## Build Process Overview
The build is a **multi-stage pipeline** designed for ARM64 Alpine Linux, orchestrated by the root [Makefile](Makefile):
1. **`make base`**: Builds a PostGIS-enabled PostgreSQL base image from upstream sources
(no official ARM64 Alpine PostGIS images exist, so we compile from `docker-postgis` repo)
2. **`make dev-image`**: Creates a cached builder image with PostgreSQL headers, `clang`, `llvm`, and build tools
3. **`make dist`**: Compiles the `base58id` extension inside the dev container and stages installed files to `./dist/`
4. **`make ext`**: Builds the final runtime image by copying `dist/usr/` into the PostGIS base
5. **`make all`**: Runs the full pipeline (`base` → `dev-image` → `dist` → `ext`)
## Usage
### Quick Start
```bash
# Build everything (takes ~10-15 min on first run due to PostGIS compilation)
make all
# Run a test container
make run
# Connect to the database
docker exec -it pg-test psql -U postgres
```
### Using the Extension
```sql
-- Enable the extension
CREATE EXTENSION base58id;
-- Create a table with base58id primary key
CREATE TABLE events (
id base58id PRIMARY KEY,
payload jsonb
);
-- Insert a Snowflake-style ID (e.g., from application)
-- Note: All base58id values are zero-padded to 11 characters
INSERT INTO events VALUES ('1111MKNMDHF', '{"event": "user.login"}');
-- Query by ID (displays as 11-char base58, compares as uint64)
SELECT * FROM events WHERE id = '1111MKNMDHF';
-- Cast to/from bigint (output is always 11 characters)
SELECT '1111MKNMDHF'::base58id::bigint; -- 987654321
SELECT 987654321::bigint::base58id; -- '1111MKNMDHF'
SELECT 0::bigint::base58id; -- '11111111111'
-- Range queries work naturally (IDs are time-ordered if using Snowflake)
SELECT id, payload FROM events WHERE id > '1111MKNMDHF' ORDER BY id LIMIT 10;
```
## Makefile Targets
| Target | Description |
|--------------|-----------------------------------------------------------------------------|
| `base` | Build PostGIS base image from upstream (ARM64 only) |
| `dev-image` | Build cached builder image with PostgreSQL dev headers + clang/llvm |
| `dist` | Compile extension and stage to `./dist/` |
| `ext` | Build final runtime image (PostGIS + base58id extension) |
| `all` | Full pipeline (default) |
| `run` | Start test container with extension pre-installed |
| `clean` | Remove `./dist/` directory |
## Configuration
Edit variables at the top of [Makefile](Makefile):
```makefile
PG_MAJOR ?= 17 # PostgreSQL version
POSTGIS_REF ?= 17-3.4-alpine # PostGIS upstream tag
PLATFORMS ?= linux/arm64 # Target architecture
REGISTRY ?= local # Image registry prefix
```
For **multi-platform builds** (e.g., AMD64 + ARM64), change `PLATFORMS` and ensure Docker Buildx is configured.
## Development Workflow
### Local Extension Development
```bash
# Edit extension/base58id.c or extension/base58id--1.0.sql
vim extension/base58id.c
# Rebuild and test
make dist ext run
docker exec -it pg-test psql -U postgres -c "DROP EXTENSION base58id; CREATE EXTENSION base58id;"
```
### Testing Changes
```bash
# Run container with auto-loaded extension
make run
# Connect and test
docker exec -it pg-test psql -U postgres <