hummer

package module
v0.0.0-...-e143326 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

README

hummer

Golang ORM 封装,基于 uptrace/bun 提供更简洁的泛型 Service/Repository API、自动迁移与 Schema 同步、分页与条件构建、事务支持、外键管理、以及可配置的日志输出。

安装

  • 运行 go get github.com/tomoncle/hummer

快速开始

  1. 定义模型
package model

import (
    "github.com/uptrace/bun"
)

type SystemConfig struct {
    bun.BaseModel `bun:"table:system_config"`

    ID    int64  `bun:"id,pk,autoincrement"`
    Name  string `bun:"name,unique:uk_system_config_name,notnull,type:varchar(64)"`
    Value string `bun:"value,type:text" hummer:"rename:cfg_value"`
}
  1. 注册模型
import "github.com/tomoncle/hummer/database"

func init() {
    database.RegisteredModel((*SystemConfig)(nil), 10)
}
  1. 初始化数据库
package main

import (
    "context"
    "github.com/tomoncle/hummer/database"
)

func main() {
    cfg := &database.Config{
        ConnectionConfig: database.ConnectionConfig{
            Type:     "mysql",        // 支持 mysql / dameng / postgres / sqlite / kingbase
            Host:     "127.0.0.1",
            Port:     3306,
            Username: "root",
            Password: "",
            DBName:   "who",
            EnableQueryLog: true,
        },
    }

    _, err := database.InitDB(cfg)
    if err != nil { panic(err) }
    defer func() { _ = database.CloseDB() }()

    _ = context.Background()
}

配置文件示例

仓库提供了完整注释版 TOML 示例:configs/hummer.example.toml。

Hummer 的数据库入口是 database.Config。如果你希望直接使用框架提供的 TOML 加载器,可以这样写:

import (
    hummerconfig "github.com/tomoncle/hummer/config"
    "github.com/tomoncle/hummer/database"
)

cfg, err := hummerconfig.LoadToml("configs/hummer.toml")
if err != nil {
    panic(err)
}

cfg.ApplyLogger() // 可选:应用 [logger] 配置,需要在创建 logger 前调用。
_, err = database.InitDB(cfg.DatabaseConfig())
if err != nil {
    panic(err)
}

如果你的项目已有自己的大配置文件,可以把 Hummer 配置作为子结构体嵌进去:

name = "example-api"

[hummer.connection_config]
type = "mysql"
host = "127.0.0.1"
port = 3306
username = "root"
password = "change-me"
dbname = "example"
conn_max_lifetime = "1h"
connect_timeout = "10s"

[hummer.data_migrate_config]
enable_migrate_on_startup = true
enable_schema_sync = true
schema_sync_dry_run = true
type AppConfig struct {
    Name   string                    `toml:"name"`
    Hummer hummerconfig.HummerConfig `toml:"hummer"`
}

var appCfg AppConfig
if err := hummerconfig.LoadTomlInto("configs/app.toml", &appCfg); err != nil {
    panic(err)
}

_, err := database.InitDB(appCfg.Hummer.DatabaseConfig())
if err != nil {
    panic(err)
}

CRUD 与查询(使用 Service)

import (
    "context"
    "github.com/tomoncle/hummer"
    "github.com/tomoncle/hummer/types"
)

svc := hummer.NewService[SystemConfig]()
ctx := context.Background()

// 创建
_ = svc.Save(ctx, &SystemConfig{Name: "site_title", Value: "Hummer"})

// 获取
cfg, _ := svc.Get(ctx, 1)

// 列表(条件)
cb := types.NewConditionBuilder().AND("name = ?", "site_title").Condition()
list, _ := svc.List(ctx, cb)

// 分页与排序
page := types.NewPageRequest(1, 10, cb, []string{"id DESC"})
pg, _ := svc.Page(ctx, page)

// 条件查询
raw, _ := svc.Query(ctx, "name = ?", "site_title")

事务

import "github.com/tomoncle/hummer/database"

db := database.GetDB()
tx, err := db.BeginTx(ctx, nil)
if err != nil { panic(err) }
defer func() { _ = tx.Rollback() }()

err = hummer.NewService[SystemConfig]().SaveWithTx(ctx, tx, &SystemConfig{Name: "k", Value: "v"})
if err != nil { panic(err) }

if err := tx.Commit(); err != nil { panic(err) }

Schema 同步与迁移

  • EnableMigrateOnStartup:启动时执行迁移(创建迁移表,执行已注册迁移)。
  • EnableSchemaSync:根据 bun 标签推断目标表结构并与现有结构比对,同步列与索引。
  • 列标签支持:type:...、notnull、default:...、pk、autoincrement、unique[:name]。
  • 重命名列:通过 hummer:"rename:old_name" 标记,用于在同步时将旧列改为新列。

外键管理

  • 通过配置启用:DataMigrateConfig.EnableForeignKey = true。
  • 支持从 YAML 文件加载外键:DataMigrateConfig.ForeignKeyFile。

示例 foreign_keys.yaml:

foreign_keys:
  - table: system_config
    column: user_id
    reference_table: users
    reference_column: id
    on_delete: CASCADE
    on_update: NO ACTION
    constraint_name: fk_system_config_user

数据初始化(SQL 文件)

  • 配置 DataInitConfig.Filepath 为 SQL 根目录,Env 为环境名(如 development)。
  • DataInitConfig.Environment 是旧的长字段兼容写法;如果 Env 和 Environment 同时配置,Environment 优先。
  • 初始化时会先读取公共 SQL 目录:DataInitConfig.Filepath + "/common"。
  • 然后读取环境 SQL 目录:DataInitConfig.Filepath + "/envs/" + DataInitConfig.Env。
  • 为兼容旧项目,如果 envs/<env> 不存在,会回退读取旧目录:DataInitConfig.Filepath + "/environments/" + DataInitConfig.Env。
  • 如果 envs/<env> 和 environments/<env> 同时存在,只读取 envs/<env>,避免同名 SQL 被重复发现或 data_sync 迁移记录冲突。
  • 执行优先级:common 目录先执行,环境目录后执行;同一目录内按文件名前缀数字排序,没有数字前缀时默认排到后面。
  • 执行:database.InitData() 或 database.InitDataWithSQL("development")。

使用 Repository(可选)

import "github.com/tomoncle/hummer/repository"

repo := repository.NewRepository[SystemConfig](database.GetDB())
entities, _ := repo.List(ctx, cb)
pagination, _ := repo.Page(ctx, types.NewPageRequest(1, 20, nil, nil))

日志配置(可选)

import "github.com/tomoncle/hummer/utils"

utils.ConfigureFileLog("logs", 7, false)      // 文件日志按天切分
utils.ConfigureFileLogFormat("json")           // 文件日志格式:json/text
utils.ConfigureConsoleLogFormat("text")        // 控制台日志格式:json/text
utils.ConfigureLogLevel("info")                // 统一日志级别

lg := utils.NewLogger("APP")
lg.Info("service started")

健康检查与统计

hs := database.GetHealthStatus(ctx) // { healthy, connected, response_time, ... }
stats := database.GetDatabaseStats() // 连接池统计

环境变量覆盖(节选)

  • DB_HOST
  • DB_PORT
  • DB_USERNAME
  • DB_PASSWORD
  • DB_NAME
  • DB_ADMIN_NAME
  • DB_SSLMODE
  • DB_MAX_IDLE_CONNS
  • DB_MAX_OPEN_CONNS
  • DB_CONN_MAX_LIFETIME
  • DB_ENABLE_QUERY_LOG

兼容数据库

  • MySQL、Dameng(达梦,原生驱动 / MySQL 兼容模式)、PostgreSQL、SQLite、KingbaseES(人大金仓)

达梦说明

  • 配置 ConnectionConfig.Type = "dameng" 时,框架会优先走达梦原生 Go 驱动 github.com/fengzehao/dm-go-driver,连接串形如 dm://user:password@host:port/dbname。
  • 如需继续使用达梦 MySQL 兼容协议,可显式配置 ConnectionConfig.Type = "dameng-mysql"。
  • 当前 Bun 没有原生达梦方言,框架在 SQL 生成层仍复用 MySQL 家族能力,并额外对达梦的连接、冲突写入、错误识别与自动建库探测做了专门处理。
  • AutoCreate=true 时,原生达梦会按 DBName 作为目标 schema 处理:
    • 通过 SYS.SYSOBJECTS 中 TYPE$='SCH' 探测 schema 是否存在
    • 不存在时执行 CREATE SCHEMA "<DBName>" AUTHORIZATION "<Username>"
    • 这条路径不再依赖 INFORMATION_SCHEMA 或 SHOW DATABASES
  • 达梦原生驱动路径默认连接字符集为 utf8;如环境需要,可通过 ConnectionConfig.Charset 覆盖连接参数与自动建库字符集。
  • 如需通过指定管理库执行达梦自动建库探测,可设置 ConnectionConfig.AdminDBName 或环境变量 DB_ADMIN_NAME。
  • 当前仓库内已提供达梦专项集成测试入口,覆盖:
    • 连接初始化与迁移
    • 基础 CRUD
    • SaveOrUpdate Upsert
    • 显式事务提交/回滚
    • 条件过滤与分页
    • 重复键错误映射
    • NOT NULL / 外键 / CHECK 约束错误映射
    • Schema Sync 的列重命名 / 新增列 / 唯一索引 / 列定义修改

示例配置:

cfg := &database.Config{
    ConnectionConfig: database.ConnectionConfig{
        Type:       "dameng",
        Host:       "127.0.0.1",
        Port:       5236,
        Username:   "SYSDBA",
        Password:   "password",
        DBName:     "example",
        AutoCreate: false,
    },
}

人大金仓说明

  • 配置 ConnectionConfig.Type = "kingbase" 即可启用人大金仓支持。
  • 底层驱动使用 gitea.com/kingbase/gokb,Bun 方言复用 PostgreSQL 家族能力。
  • AutoCreate=true 时,默认连接管理库 security 检查并创建目标库;如环境不同,可通过 ConnectionConfig.AdminDBName 或环境变量 DB_ADMIN_NAME 覆盖。
  • 已验证能力:
    • 连接初始化
    • 自动迁移
    • Schema 同步
    • 基础 CRUD
    • ON CONFLICT Upsert
    • 显式事务提交/回滚
    • 条件过滤与分页
    • 主键序列自动补齐
    • 自定义唯一约束名保留
    • SQL 错误识别:重复键 / 外键 / CHECK 约束
    • AutoCreate 管理库探测失败时回退连接业务库

已知行为:

  • 当模型字段带有 default:... 标签时,Save/Create 在零值场景下可能沿用数据库默认值,而不是显式写入零值。
  • 例如:bool 字段声明为 bun:"enabled,notnull,default:true" 时,Enabled: false 在插入阶段可能落成数据库默认值 true。
  • 对这类字段,如果需要显式覆盖默认值,建议使用 Update 或 SaveOrUpdate。
  • 该行为来自 Bun 对带默认值字段的插入策略,不是人大金仓独有差异;MySQL/PostgreSQL/SQLite 也可能表现一致。
  • 在当前已验证的 Kingbase8 环境中,向 NOT NULL varchar 列显式插入 NULL 时,数据库可能不会抛出 NOT NULL 约束异常,而是将值折算为空字符串 ""。
  • 因此,NOT NULL 违规是否能稳定映射为 NotNullViolationErr,取决于实际 Kingbase 实例参数和行为模式,不能假定所有环境都与 PostgreSQL 完全一致。
  • 若 AutoCreate 所需的管理库或系统视图不可访问,框架会记录告警并继续尝试连接业务库,不会因为自动建库探测失败而直接中断初始化。

示例配置:

cfg := &database.Config{
    ConnectionConfig: database.ConnectionConfig{
        Type:     "kingbase",
        Host:     "127.0.0.1",
        Port:     4321,
        Username: "system",
        Password: "password",
        DBName:   "example",
        AdminDBName: "security",
        SSLMode:  "disable",
    },
}

集成测试

  • 通用集成测试读取以下环境变量:
    • TEST_DB_TYPE
    • TEST_DB_HOST
    • TEST_DB_PORT
    • TEST_DB_USERNAME
    • TEST_DB_PASSWORD
    • TEST_DB_NAME
  • 人大金仓专项测试读取以下环境变量:
    • KINGBASE_TEST_HOST
    • KINGBASE_TEST_PORT
    • KINGBASE_TEST_USERNAME
    • KINGBASE_TEST_PASSWORD
    • KINGBASE_TEST_DBNAME
    • KINGBASE_TEST_SSLMODE
  • 达梦专项测试读取以下环境变量:
    • DAMENG_TEST_HOST
    • DAMENG_TEST_PORT
    • DAMENG_TEST_USERNAME
    • DAMENG_TEST_PASSWORD
    • DAMENG_TEST_DBNAME
  • 未提供这些环境变量时,相关测试会自动跳过。

运行示例:

$env:KINGBASE_TEST_HOST="127.0.0.1"
$env:KINGBASE_TEST_PORT="4321"
$env:KINGBASE_TEST_USERNAME="kingbase"
$env:KINGBASE_TEST_PASSWORD="your_password"
$env:KINGBASE_TEST_DBNAME="test"
go test ./tests -run TestKingbase -v
$env:DAMENG_TEST_HOST="127.0.0.1"
$env:DAMENG_TEST_PORT="5236"
$env:DAMENG_TEST_USERNAME="SYSDBA"
$env:DAMENG_TEST_PASSWORD="your_password"
$env:DAMENG_TEST_DBNAME="test"
go test ./tests -run TestDameng -v

参考

  • ORM: github.com/uptrace/bun

Documentation

Overview

Package hummer provides a lightweight service layer built on Bun and integrates the repository and database packages for common data access.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Service

type Service[T any] interface {
	// Get returns a single entity by its identifier.
	Get(ctx context.Context, id any) (*T, error)

	// All returns all entities.
	All(ctx context.Context) ([]*T, error)

	// List returns entities that match the provided filter.
	List(ctx context.Context, filter *types.Condition) ([]*T, error)

	// Query executes a raw query and maps the results to entities.
	Query(ctx context.Context, query string, args ...interface{}) ([]*T, error)

	// Page returns a paginated list of entities.
	Page(ctx context.Context, page *types.PageRequest) (*types.Pagination[T], error)

	// Update modifies an existing entity.
	Update(ctx context.Context, model ...*T) error

	// Delete removes an entity by its identifier.
	Delete(ctx context.Context, id ...any) error

	// Save inserts one or more new entities.
	Save(ctx context.Context, model ...*T) error

	// SaveOrUpdate upserts entities based on fields and duplicate keys.
	SaveOrUpdate(ctx context.Context, fields []string, duplicateKeys []string, model ...*T) error

	// SaveWithTx inserts entities within an existing transaction.
	SaveWithTx(ctx context.Context, tx *bun.Tx, model ...*T) error

	// SaveOrUpdateWithTx upserts entities within a transaction.
	SaveOrUpdateWithTx(ctx context.Context, tx *bun.Tx, fields []string, duplicateKeys []string, model ...*T) error

	// UpdateWithTx updates an entity within a transaction.
	UpdateWithTx(ctx context.Context, tx *bun.Tx, model ...*T) error

	// DeleteWithTx removes an entity within a transaction.
	DeleteWithTx(ctx context.Context, tx *bun.Tx, id ...any) error

	// SelectBuilder returns a Bun select query builder for the entity.
	SelectBuilder() *bun.SelectQuery

	// InsertBuilder returns a Bun insert query builder for the entity.
	InsertBuilder() *bun.InsertQuery

	// UpdateBuilder returns a Bun update query builder for the entity.
	UpdateBuilder() *bun.UpdateQuery

	// DeleteBuilder returns a Bun delete query builder for the entity.
	DeleteBuilder() *bun.DeleteQuery
}

func NewService

func NewService[T any]() Service[T]

NewService returns a default Service implementation using the generic repository backed by the global database connection.

func NewServiceWithDB

func NewServiceWithDB[T any](db *bun.DB) Service[T]

NewServiceWithDB returns a default Service implementation using the provided Bun DB instead of the global database connection.

func NewServiceWithRepository

func NewServiceWithRepository[T any](repo repository.Repository[T]) Service[T]

NewServiceWithRepository returns a Service implementation backed by the provided repository.

Directories

Path Synopsis
Package config provides optional TOML loading helpers for Hummer.
Package config provides optional TOML loading helpers for Hummer.
Package database provides connection management, migrations, foreign key handling, SQL initialization, configuration types, logging, health checks, and related utilities built on top of Bun.
Package database provides connection management, migrations, foreign key handling, SQL initialization, configuration types, logging, health checks, and related utilities built on top of Bun.
Package repository provides a generic repository abstraction built on Bun for CRUD operations, querying, pagination, transactions, and upsert support.
Package repository provides a generic repository abstraction built on Bun for CRUD operations, querying, pagination, transactions, and upsert support.
Package types contains shared data structures used across the project, including enums, JSON helpers, query filters, and pagination models.
Package types contains shared data structures used across the project, including enums, JSON helpers, query filters, and pagination models.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
⌂ 换网址