sumup/typeid
GitHub: sumup/typeid
一个基于 UUIDv7/UUIDv4 的 Go 语言类型安全全局唯一标识符库,通过类型前缀在编译期区分不同实体的 ID。
Stars: 45 | Forks: 0
# TypeID
[](https://github.com/sumup/typeid/)
[](https://pkg.go.dev/github.com/sumup/typeid)
[](https://github.com/sumup/typeid/actions/workflows/ci.yml)
[](./LICENSE)
[](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, 唯一标识符, 开发库, 数据库主键, 日志审计, 测试用例