{"id":31794249,"url":"https://github.com/curt/postgis-base58id","last_synced_at":"2026-06-30T21:31:49.403Z","repository":{"id":318293922,"uuid":"1069792479","full_name":"curt/postgis-base58id","owner":"curt","description":"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.","archived":false,"fork":false,"pushed_at":"2025-10-06T09:30:32.000Z","size":11,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"dev","last_synced_at":"2025-10-14T20:39:57.012Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/curt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-04T16:25:36.000Z","updated_at":"2025-10-06T09:30:35.000Z","dependencies_parsed_at":"2025-10-06T11:30:55.785Z","dependency_job_id":"0d870c3d-47d6-4d29-8c17-10a08c287503","html_url":"https://github.com/curt/postgis-base58id","commit_stats":null,"previous_names":["curt/postgis-base58id"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/curt/postgis-base58id","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curt%2Fpostgis-base58id","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curt%2Fpostgis-base58id/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curt%2Fpostgis-base58id/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curt%2Fpostgis-base58id/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/curt","download_url":"https://codeload.github.com/curt/postgis-base58id/tar.gz/refs/heads/dev","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curt%2Fpostgis-base58id/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34984784,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-30T02:00:05.919Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-10-10T19:21:12.004Z","updated_at":"2026-06-30T21:31:49.383Z","avatar_url":"https://github.com/curt.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# postgis-base58id\n\nA 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.\n\n## Features\n\n- **Compact storage**: 8 bytes, pass-by-value (same as `bigint`)\n- **Base58 encoding**: Bitcoin alphabet (no `0OIl` ambiguity), zero-padded to 11 characters\n- **Full operator support**: Comparison operators (`\u003c`, `\u003c=`, `=`, `\u003e=`, `\u003e`, `\u003c\u003e`)\n- **Indexable**: B-tree and hash operator classes included\n- **Cast support**: Bidirectional casts with `bigint` and `text`\n- **Binary I/O**: Efficient `COPY` and client protocol support\n- **Uniform hash distribution**: Uses PostgreSQL's `hash_any()` for optimal hash index performance\n\n## Project Structure\n\n```\n.\n├── extension/\n│   ├── base58id.c              # C implementation (encoding, I/O, operators)\n│   ├── base58id--1.0.sql       # SQL type/function definitions\n│   ├── base58id.control        # Extension metadata\n│   └── Makefile                # PGXS build (for \"make install\")\n├── docker/\n│   └── initdb/\n│       └── 01-enable-base58id.sql  # Auto-enable extension on container init\n├── Dockerfile.ext              # Final runtime image (FROM PostGIS base + extension)\n├── Makefile                    # Orchestrates multi-stage build\n└── dist/                       # Staged extension files (created by \"make dist\")\n```\n\n## Build Process Overview\n\nThe build is a **multi-stage pipeline** designed for ARM64 Alpine Linux, orchestrated by the root [Makefile](Makefile):\n\n1. **`make base`**: Builds a PostGIS-enabled PostgreSQL base image from upstream sources\n   (no official ARM64 Alpine PostGIS images exist, so we compile from `docker-postgis` repo)\n\n2. **`make dev-image`**: Creates a cached builder image with PostgreSQL headers, `clang`, `llvm`, and build tools\n\n3. **`make dist`**: Compiles the `base58id` extension inside the dev container and stages installed files to `./dist/`\n\n4. **`make ext`**: Builds the final runtime image by copying `dist/usr/` into the PostGIS base\n\n5. **`make all`**: Runs the full pipeline (`base` → `dev-image` → `dist` → `ext`)\n\n## Usage\n\n### Quick Start\n\n```bash\n# Build everything (takes ~10-15 min on first run due to PostGIS compilation)\nmake all\n\n# Run a test container\nmake run\n\n# Connect to the database\ndocker exec -it pg-test psql -U postgres\n```\n\n### Using the Extension\n\n```sql\n-- Enable the extension\nCREATE EXTENSION base58id;\n\n-- Create a table with base58id primary key\nCREATE TABLE events (\n    id base58id PRIMARY KEY,\n    payload jsonb\n);\n\n-- Insert a Snowflake-style ID (e.g., from application)\n-- Note: All base58id values are zero-padded to 11 characters\nINSERT INTO events VALUES ('1111MKNMDHF', '{\"event\": \"user.login\"}');\n\n-- Query by ID (displays as 11-char base58, compares as uint64)\nSELECT * FROM events WHERE id = '1111MKNMDHF';\n\n-- Cast to/from bigint (output is always 11 characters)\nSELECT '1111MKNMDHF'::base58id::bigint;       -- 987654321\nSELECT 987654321::bigint::base58id;            -- '1111MKNMDHF'\nSELECT 0::bigint::base58id;                    -- '11111111111'\n\n-- Range queries work naturally (IDs are time-ordered if using Snowflake)\nSELECT id, payload FROM events WHERE id \u003e '1111MKNMDHF' ORDER BY id LIMIT 10;\n```\n\n## Makefile Targets\n\n| Target       | Description                                                                 |\n|--------------|-----------------------------------------------------------------------------|\n| `base`       | Build PostGIS base image from upstream (ARM64 only)                        |\n| `dev-image`  | Build cached builder image with PostgreSQL dev headers + clang/llvm       |\n| `dist`       | Compile extension and stage to `./dist/`                                   |\n| `ext`        | Build final runtime image (PostGIS + base58id extension)                  |\n| `all`        | Full pipeline (default)                                                    |\n| `run`        | Start test container with extension pre-installed                         |\n| `clean`      | Remove `./dist/` directory                                                 |\n\n## Configuration\n\nEdit variables at the top of [Makefile](Makefile):\n\n```makefile\nPG_MAJOR        ?= 17                          # PostgreSQL version\nPOSTGIS_REF     ?= 17-3.4-alpine               # PostGIS upstream tag\nPLATFORMS       ?= linux/arm64                 # Target architecture\nREGISTRY        ?= local                       # Image registry prefix\n```\n\nFor **multi-platform builds** (e.g., AMD64 + ARM64), change `PLATFORMS` and ensure Docker Buildx is configured.\n\n## Development Workflow\n\n### Local Extension Development\n\n```bash\n# Edit extension/base58id.c or extension/base58id--1.0.sql\nvim extension/base58id.c\n\n# Rebuild and test\nmake dist ext run\ndocker exec -it pg-test psql -U postgres -c \"DROP EXTENSION base58id; CREATE EXTENSION base58id;\"\n```\n\n### Testing Changes\n\n```bash\n# Run container with auto-loaded extension\nmake run\n\n# Connect and test\ndocker exec -it pg-test psql -U postgres \u003c\u003cSQL\n  CREATE EXTENSION base58id;\n  SELECT 0::bigint::base58id;                    -- '11111111111'\n  SELECT 1::bigint::base58id;                    -- '11111111112'\n  SELECT '11111111112'::base58id::bigint;        -- 1\nSQL\n```\n\n## Notes for Time-Based Flake IDs\n\nIf using Snowflake/Sonyflake-style IDs (timestamp in MSBs):\n\n- ✅ **B-tree indexes**: Excellent clustering and range query performance\n- ✅ **Hash indexes**: Use `hash_any()` for uniform distribution (see [base58id.c:217](extension/base58id.c#L217))\n- ⚠️ **Hot spot contention**: Monotonic IDs cause right-edge B-tree growth; tune `fillfactor` if needed\n\n## Author\n\n**Curt Gilman**\n\n## License\n\nMIT License - see [LICENSE](LICENSE) for details\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcurt%2Fpostgis-base58id","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcurt%2Fpostgis-base58id","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcurt%2Fpostgis-base58id/lists"}