A Go library providing ULID-based unique identifier management with comprehensive database support.
- ULID-based IDs: Universally Unique Lexicographically Sortable Identifiers
- JSON Support: Built-in JSON marshaling/unmarshaling
- Database Compatibility: Works with MongoDB, MySQL, PostgreSQL, and SQLite
- Type Safety: Strong typing with Go's type system
- Zero Dependencies: Core library only depends on
github.com/oklog/ulid/v2 - Clean Architecture: Uses Go workspaces to completely separate test dependencies
go get github.com/ieshan/idxpackage main
import (
"fmt"
"github.com/ieshan/idx"
)
func main() {
// Create a new ID
id := idx.NewID()
fmt.Println("New ID:", id.String())
// Parse from string
parsed, err := idx.FromString(id.String())
if err != nil {
panic(err)
}
// Compare IDs
if id.Compare(parsed) == 0 {
fmt.Println("IDs are equal")
}
// Check if zero
if id.IsZero() {
fmt.Println("ID is zero")
}
}This project uses Go workspaces to completely separate database dependencies from the core library, ensuring zero pollution for downstream projects.
# 1. Setup Go workspace (generates go.work, syncs deps, tidies all modules)
make setup
# 2. Run unit tests locally (fast, no Docker needed)
make test
# 3. Run all tests in Docker (unit + integration with databases)
make test-dockeridx/
├── go.mod # Core library (minimal dependencies)
├── go.sum
├── idx.go # Core library implementation
├── idx_test.go # Unit tests (no databases)
├── integration-tests/ # Separate module for database tests
│ ├── go.mod # Database dependencies isolated here
│ ├── go.sum
│ └── idx_integration_test.go # Database integration tests
├── compose.yml # Docker Compose (app + test + databases)
├── Makefile # Development orchestration commands
└── README.md
Note:
go.workandgo.work.sumare ephemeral — generated bymake setup, never committed (gitignored).
The Problem with Build Tags: Even with //go:build integration tags, Go still parses import statements and forces database dependencies into the main go.mod, polluting downstream projects.
The Workspace Solution:
- Main module (
github.com/ieshan/idx): Onlygithub.com/oklog/ulid/v2 - Test module (
integration-tests): All database drivers isolated here - True Separation: Import statements in integration tests don't affect main module
When someone runs go get github.com/ieshan/idx, they get:
- ✅ Only
github.com/oklog/ulid/v2(core dependency) - ❌ No MongoDB drivers, GORM, or any database dependencies
- ⚡ Zero dependency pollution
# Run unit tests only - ultra fast (1-2ms)
make test
# Or directly
go test -v -race -count=1 ./...
# Run integration tests locally (requires databases running on localhost)
make test-integration-local
# Run all tests locally (unit + integration)
make test-local# Run unit tests in Docker (no database needed)
make test-unit-docker
# Run integration tests in Docker (starts databases automatically)
make test-integration
# Run all tests in Docker (unit + integration)
make test-all
# Run all tests via docker compose up (single command, nakusp-style)
make test-docker# Full CI pipeline locally (vet -> build -> test)
make ci
# Full CI pipeline in Docker (vet -> build -> test-all)
make ci-docker| Target | Purpose |
|---|---|
make setup |
Generate go.work, sync deps, tidy all modules |
make tidy |
Run go mod tidy in all modules + workspace sync |
make mod-download |
Download Go modules for all modules |
make vet |
Run go vet in all modules |
make build |
Build all packages in all modules |
make clean |
Clean Go caches, remove go.work, stop Docker |
| Target | Environment | Purpose |
|---|---|---|
make test |
Local | Unit tests (default, fast) |
make test-unit |
Local | Same as test |
make test-integration-local |
Local | Integration tests (requires DBs on localhost) |
make test-local |
Local | Unit + integration tests |
make test-unit-docker |
Docker | Unit tests in Docker |
make test-integration |
Docker | Integration tests with databases |
make test-all |
Docker | Unit + integration tests with databases |
make test-docker |
Docker | All tests via docker compose up (single command) |
| Target | Environment | Purpose |
|---|---|---|
make ci |
Local | vet + build + test |
make ci-docker |
Docker | vet + build + test-all |
| Target | Purpose |
|---|---|
make db-up |
Start database services |
make db-down |
Stop all services |
make db-wait |
Wait for databases to be ready |
make shell |
Interactive shell with DBs running |
make shell-no-db |
Interactive shell without databases |
make help # Show all available targetsThe library is tested against:
- MongoDB 8.3.4 (CRUD operations with BSON)
- MariaDB 12.3.2 (Binary ID storage via GORM/MySQL driver)
- PostgreSQL 18.4 (BYTEA column support via GORM)
- SQLite (In-memory, BLOB storage via GORM)
Each database test performs comprehensive CRUD operations to ensure compatibility.
- Unit Tests: ~1-2ms (zero database dependencies)
- Integration Tests: ~100ms (includes database setup/teardown)
- Memory Usage: Minimal - IDs are 16-byte arrays
// Even with build tags, this pollutes go.mod:
//go:build integration
import (
"go.mongodb.org/mongo-driver/v2/mongo" // ← Forces into main go.mod
"gorm.io/gorm" // ← Forces into main go.mod
)Main module go.mod:
require github.com/oklog/ulid/v2 v2.1.1 # ← Only this!
integration-tests/go.mod:
require (
github.com/ieshan/idx v0.0.0-... # ← Local reference
go.mongodb.org/mongo-driver/v2 v2.7.0 # ← Isolated here
gorm.io/driver/mysql v1.6.0 # ← Isolated here
gorm.io/driver/postgres v1.6.0 # ← Isolated here
gorm.io/driver/sqlite v1.6.0 # ← Isolated here
gorm.io/gorm v1.31.2 # ← Isolated here
)
- Run
make setupto initialize the Go workspace - Make sure unit tests pass:
make test - Make sure integration tests pass:
make test-integration - Run full CI simulation:
make ci - Or use Docker for everything:
make test-docker
MIT