{"id":31794251,"url":"https://github.com/curt/postgres-base58id","last_synced_at":"2025-10-10T19:21:21.485Z","repository":{"id":318325193,"uuid":"1070749299","full_name":"curt/postgres-base58id","owner":"curt","description":null,"archived":false,"fork":false,"pushed_at":"2025-10-06T13:28:59.000Z","size":14,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-06T15:24:54.642Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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-06T11:43:10.000Z","updated_at":"2025-10-06T13:29:03.000Z","dependencies_parsed_at":"2025-10-06T15:24:56.738Z","dependency_job_id":"f767f2df-5637-4c21-a4cc-835e9d891be3","html_url":"https://github.com/curt/postgres-base58id","commit_stats":null,"previous_names":["curt/postgres-base58id"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/curt/postgres-base58id","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curt%2Fpostgres-base58id","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curt%2Fpostgres-base58id/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curt%2Fpostgres-base58id/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curt%2Fpostgres-base58id/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/curt","download_url":"https://codeload.github.com/curt/postgres-base58id/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curt%2Fpostgres-base58id/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279005034,"owners_count":26083827,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"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.528Z","updated_at":"2025-10-10T19:21:21.480Z","avatar_url":"https://github.com/curt.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# postgres-base58id\n\nPostgreSQL extension providing a native **base58id** data type: a 64-bit unsigned integer with automatic Base58 encoding for text I/O.\n\n## Purpose\n\nThis is the **second of three related projects** for building and distributing PostgreSQL C extensions:\n\n1. **postgres-dev-builder** - Builds and publishes cached toolchain images\n2. **postgres-base58id** (this project) - Compiles C extensions and publishes versioned artifacts\n3. **postgis-base58id-image** - Builds final runtime images by installing pre-compiled artifacts\n\n## Why this exists\n\nThis project takes the C extension source code and:\n- Compiles it for multiple architectures (amd64, arm64) using the dev images from project #1\n- Packages the compiled binaries (`.so`, `.control`, `.sql` files) into versioned tar.gz archives\n- Publishes these artifacts as GitHub Releases for consumption by runtime image builders (project #3)\n\nThis separates the compilation step from the runtime image, allowing:\n- **Versioned artifacts**: Each release is independently downloadable\n- **Multi-arch support**: Single release includes binaries for multiple architectures\n- **Decoupled builds**: Runtime images can be rebuilt without recompiling\n- **Matrix builds**: Support multiple PostgreSQL versions (15, 16, 17) and variants (alpine, bookworm)\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```\npostgres-base58id/\n├── extension/\n│   ├── base58id.c              # C implementation (encoding, I/O, operators)\n│   ├── base58id--1.0.sql       # SQL type/function definitions (shell type pattern)\n│   ├── base58id.control        # Extension metadata\n│   └── Makefile                # PGXS build rules\n├── .github/workflows/\n│   └── release.yml             # Multi-arch compilation and GitHub Releases\n├── Makefile                    # Orchestrates compilation and packaging\n└── README.md                   # This file\n```\n\n## Getting Started\n\n### Prerequisites\n\n1. **Docker** with buildx support\n2. **Nerdbank.GitVersioning (NBGV)** for version management:\n   - Install: `dotnet tool install -g nbgv`\n   - Generates version numbers from git history and [version.json](version.json)\n3. **Access to postgres-dev images** from project #1:\n   - Either build locally: `cd ../postgres-dev-builder \u0026\u0026 make build-local`\n   - Or use published images: `ghcr.io/yourorg/postgres-dev:17-alpine`\n\n### Configuration\n\nUpdate registry settings in [Makefile](Makefile):\n```makefile\nREGISTRY ?= ghcr.io/yourorg  # Change to your GitHub org/username\n```\n\n### Local Development\n\n```bash\n# Test compilation (single platform)\nmake test PG_MAJOR=17 VARIANT=alpine\n\n# Compile for all platforms\nmake compile PG_MAJOR=17 VARIANT=alpine PLATFORMS=linux/arm64,linux/amd64\n\n# Create release packages\nmake package PG_MAJOR=17 VARIANT=alpine\n\n# Clean build artifacts\nmake clean\n```\n\n### Creating a Release\n\n1. **Tag the release:**\n   ```bash\n   git tag -a v1.0.0 -m \"Release version 1.0.0\"\n   git push origin v1.0.0\n   ```\n\n2. **GitHub Actions automatically:**\n   - Compiles for all PostgreSQL versions (15, 16, 17)\n   - Compiles for all variants (alpine, bookworm)\n   - Compiles for all architectures (amd64, arm64)\n   - Creates tar.gz archives for each combination\n   - Publishes to GitHub Releases\n\n3. **Download artifacts:**\n   ```bash\n   # Example release URLs:\n   # base58id-1.0.0-pg17-alpine-arm64.tar.gz\n   # base58id-1.0.0-pg17-alpine-amd64.tar.gz\n   # base58id-1.0.0-pg17-bookworm-arm64.tar.gz\n   # ... etc\n   ```\n\n## Makefile Targets\n\n| Target     | Description                                           |\n|------------|-------------------------------------------------------|\n| `compile`  | Compile extension for specified platforms             |\n| `package`  | Create tar.gz release archives                        |\n| `test`     | Test compilation in dev container                     |\n| `all`      | Compile and package (default)                         |\n| `clean`    | Remove dist/ and releases/ directories                |\n\n## Usage Example\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 (zero-padded to 11 characters)\nINSERT INTO events VALUES ('1111MKNMDHF', '{\"event\": \"user.login\"}');\n\n-- Query by ID\nSELECT * FROM events WHERE id = '1111MKNMDHF';\n\n-- Cast to/from bigint\nSELECT '1111MKNMDHF'::base58id::bigint;  -- 987654321\nSELECT 987654321::bigint::base58id;       -- '1111MKNMDHF'\nSELECT 0::bigint::base58id;               -- '11111111111'\n```\n\n## Architecture Decisions\n\n1. **Why separate compilation from runtime images?**\n   - Faster iteration: Rebuild runtime images without recompiling\n   - Versioned artifacts: Pin to specific extension versions\n   - Smaller runtime images: No build tools needed\n\n2. **Why matrix builds?**\n   - Support multiple PostgreSQL versions simultaneously\n   - Support both Debian (bookworm) and Alpine variants\n   - Enable users to choose their preferred base image\n\n3. **Why GitHub Releases?**\n   - Permanent, versioned storage for binaries\n   - Easy downloading via URLs in Dockerfiles\n   - Automatic changelog generation\n\n4. **Why tar.gz instead of .deb/.rpm?**\n   - Simpler cross-platform support\n   - Direct `tar -xzf` in Dockerfiles\n   - Works with both Alpine (apk) and Debian (apt)\n\n## Initial Setup\n\n1. **Initialize git repository:**\n   ```bash\n   cd /path/to/postgres-base58id\n   git init\n   git add .\n   git commit -m \"Initial commit: base58id extension\"\n   ```\n\n2. **Test local build:**\n   ```bash\n   make test PG_MAJOR=17 VARIANT=alpine\n   ```\n\n3. **Create GitHub repository and push:**\n   ```bash\n   git remote add origin git@github.com:yourorg/postgres-base58id.git\n   git push -u origin main\n   ```\n\n4. **Create first release:**\n   ```bash\n   git tag -a v1.0.0 -m \"Initial release\"\n   git push origin v1.0.0\n   ```\n\n5. **Verify GitHub Actions:**\n   - Check Actions tab for workflow execution\n   - Check Releases section for published artifacts\n\n## Extension Implementation Notes\n\n### Shell Type Pattern\n\nThe SQL file ([extension/base58id--1.0.sql](extension/base58id--1.0.sql)) uses the \"shell type\" pattern required by PostgreSQL:\n\n1. Create shell type: `CREATE TYPE base58id;`\n2. Define I/O functions that reference the shell type\n3. Complete type definition with I/O functions\n\nThis order is critical - the I/O functions (`base58id_in`, `base58id_out`, etc.) must exist before the full `CREATE TYPE` statement.\n\n### Hash Distribution\n\nFor time-based IDs (Snowflake/Sonyflake), the hash function uses PostgreSQL's `hash_any()` to ensure uniform distribution despite monotonic values. See [extension/base58id.c](extension/base58id.c) for implementation.\n\n## Project History\n\nOriginally part of a monolithic `postgis-base58id` project that mixed:\n- Building PostGIS base images from source\n- Building dev toolchain images\n- Compiling C extensions\n- Building final runtime images\n\nSplit into three focused projects (Oct 2025) to enable:\n- Independent versioning of extension code\n- Reusable compilation artifacts\n- Faster iteration on runtime images\n\n## Next Steps\n\nAfter setting up this project:\n1. Ensure **postgres-dev-builder** images are available in your registry\n2. Create a release tag to trigger artifact builds\n3. Use the published artifacts in **postgis-base58id-image** (project #3)\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%2Fpostgres-base58id","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcurt%2Fpostgres-base58id","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcurt%2Fpostgres-base58id/lists"}