sumup/typeid

GitHub: sumup/typeid

一个基于 UUIDv7/UUIDv4 的 Go 语言类型安全全局唯一标识符库,通过类型前缀在编译期区分不同实体的 ID。

Stars: 45 | Forks: 0

# TypeID [![Stars](https://img.shields.io/github/stars/sumup/typeid?style=social)](https://github.com/sumup/typeid/) [![Go Reference](https://pkg.go.dev/badge/github.com/sumup/typeid.svg)](https://pkg.go.dev/github.com/sumup/typeid) [![CI Status](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/7fda85ccab170455.svg)](https://github.com/sumup/typeid/actions/workflows/ci.yml) [![License](https://img.shields.io/github/license/sumup/typeid)](./LICENSE) [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.1%20adopted-ff69b4.svg)](https://github.com/sumup/typeid/tree/main/CODE_OF_CONDUCT.md)
TypeID 是一种基于 [UUIDv7 标准](https://datatracker.ietf.org/doc/html/rfc9562)的*类型安全、全局唯一标识符*的草案标准。它的特性,特别是 k-sortability(可按键排序性),使其非常适合作为 PostgreSQL 等传统数据库系统的主标识符。然而,k-sortability 并不总是理想的。例如,出于安全原因,您可能需要一个具有高随机熵的标识符。此外,在 CockroachDB 等分布式数据库系统中,拥有可按键排序的主键可能会导致热点和性能问题。 虽然这个包的灵感来自原始的 typeid-go 包([github.com/jetify-com/typeid-go](https://github.com/jetify-com/typeid-go)),但它提供了多种 ID 类型: - `typeid.Sortable` 基于 UUIDv7[^UUIDv7] 并且是 k-sortable 的。它的实现遵循草案标准。后缀部分使用**小写** crockford base32 编码。 - `typeid.Random` 也基于 UUIDv4[^UUIDv4] 并且是完全随机的。与 `typeid.Sortable` 不同,它的后缀部分使用**大写** crockford base32 编码。 有关更多详细信息,请参阅相应的类型文档。 ## 安装 ``` go get github.com/sumup/typeid ``` # 用法 要创建新的 ID 类型,请定义一个实现了 `typeid.Prefix` 接口的 prefix 类型。然后,为您的 ID 类型定义一个 TypeAlias,将其指向 `typeid.Random` 或 `typeid.Sortable`,并以您的 prefix 类型作为泛型参数。 示例: ``` import "github.com/sumup/typeid" type UserPrefix struct{} func (UserPrefix) Prefix() string { return "user" } type UserID = typeid.Sortable[UserPrefix] userID, err := typeid.New[UserID]() if err != nil { fmt.Println("create user id:", err) } fmt.Println(userID) // --> user_01hf98sp99fs2b4qf2jm11hse4 ``` # 数据库支持 此包中的 ID 类型可与 [database/sql](https://pkg.go.dev/database/sql) 和 [github.com/jackc/pgx](https://pkg.go.dev/github.com/jackc/pgx/v5) 一起使用。 使用标准库 SQL 时,ID 将以其字符串表示形式存储,并可以据此进行扫描和赋值。使用 pgx 时,TEXT 和 UUID 列都可以直接使用。但是,请注意,除非您在数据库层采取额外措施,否则在使用 UUID 列时类型信息会丢失。请注意您的标识符语义,尤其是在复杂的 JOIN 查询中。 如果在 PostgreSQL 中使用 `pgx`,您可以生成 UUIDv4(供 `typeid.Random` 使用)作为主键的默认值: ``` CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT GEN_RANDOM_UUID(), ... ); ``` 对于 k-sortable 的 TypeID(`typeid.Sortable`,使用 UUIDv7),除非您运行的是支持这两者的 [PostgreSQL 18](https://www.thenile.dev/blog/uuidv7) 或更新版本,否则您必须在应用程序中生成 UUID: ``` -- With random TypeID CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT uuidv4(), ... ); -- With sortable TypeID CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT uuidv7(), ... ); ``` ## 与 sqlc 一起使用 通过在您的 `sqlc.yaml` 配置中使用列覆盖(column overrides),TypeID 可以与 [sqlc](https://sqlc.dev/) 无缝协作: ``` version: "2" sql: - schema: "schema.sql" queries: "queries" engine: postgresql gen: go: package: postgres out: postgres sql_package: pgx/v5 overrides: - column: users.id go_type: import: github.com/yourorg/yourproject/internal/domain type: "UserID" ``` 使用此配置,sqlc 将生成直接使用您的 TypeID 类型的 Go 代码: ``` package domain import "github.com/sumup/typeid" type UserPrefix struct{} func (UserPrefix) Prefix() string { return "user" } type UserID = typeid.Sortable[UserPrefix] type User struct { ID UserID Name string // ... other fields } ``` 然后,您可以直接在查询中使用您的 TypeID 类型: ``` -- name: CreateUser :one INSERT INTO users ( id, name ) VALUES ( @id, @name ) RETURNING *; -- name: GetUser :one SELECT * FROM users WHERE id = @id; ``` 并从 Go 中调用它们: ``` userID := typeid.Must(typeid.New[domain.UserID]()) user, err := queries.CreateUser(ctx, postgres.CreateUserParams{ ID: userID, Name: "Karl", }) ``` ## 与 oapi-codegen 一起使用 TypeID 可与 [oapi-codegen](https://github.com/oapi-codegen/oapi-codegen) 结合使用,以生成类型安全的 API 客户端和服务器。在您的 OpenAPI 规范中使用 `x-go-type` 和 `x-go-type-import` 扩展: ``` paths: /users/{user_id}: parameters: - in: path name: user_id description: The ID of the uesr to retrieve. required: true schema: type: string example: user_01hf98sp99fs2b4qf2jm11hse4 x-go-type: "domain.UserID" x-go-type-import: path: github.com/yourorg/yourproject/internal/domain components: schemas: User: type: object properties: id: type: string description: Unique identifier of the user. example: user_01hf98sp99fs2b4qf2jm11hse4 x-go-type: "domain.UserID" x-go-type-import: path: github.com/yourorg/yourproject/internal/domain name: type: string ``` 生成的代码将使用您的 TypeID 类型: ``` type User struct { Id domain.UserID `json:"id"` Name string `json:"name"` } ``` TypeID 实现了 `encoding.TextMarshaler` 和 `encoding.TextUnmarshaler`,因此它们无需任何额外配置即可用于生成的 API 代码中的 JSON 编码/解码。 ### 维护者 - [Johannes Gräger](mailto:johannes.graeger@sumup.com) - [Matouš Dzivjak](mailto:matous.dzivjak@sumup.com) 基于以下地址的 typeid Go 实现:https://github.com/jetify-com/typeid-go ,作者为 [Jetify](https://www.jetify.com/)。 修改内容在与原版相同的许可下提供。
标签:EVTX分析, Go, Ruby工具, UUID, 唯一标识符, 开发库, 数据库主键, 日志审计, 测试用例