# tcode **Repository Path**: yan-shi-kun/tcode ## Basic Information - **Project Name**: tcode - **Description**: Go语言轻量ORM,极简封装,支持基本类型,结构体,切片,分页结果映射,原始表数据映射(行,列) - **Primary Language**: Go - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 7 - **Forks**: 0 - **Created**: 2023-06-27 - **Last Updated**: 2025-06-11 ## Categories & Tags **Categories**: database-dev **Tags**: go-orm ## README # tcode # 介绍 Go语言轻量ORM,极简封装,尽可能少使用反射进行封装,支持多库,支持基本类型,结构体,切片,分页结果映射,原始表数据映射(行,列),批量新增,事务 新增,更新数据表时采用go语言类型默认值进行补充,不允许数据表中包含null列, 代码生成器,使用函数`WriteStruct`进行结构体的输出,生成出的结构体不建议手动修改,如需修改,可以copy至其他目录进行修改 # 安装教程 ```shell go get gitee.com/yan-shi-kun/tcode ``` # 支持数据库 目前仅支持Mysql,后续新增支持(PostgreSQL,SQLite,Oracle,DB2...等) # 使用说明 ## 初始化代码生成器和数据库链接 ```go // 初始化代码生成器和数据库链接 var ( conf = &Config{ Dsn: "root:root@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=true&loc=Local", DriverName: "mysql", Dialect: "mysql", MaxOpenConns: 50, MaxIdleConns: 50, ConnMaxLifetimeSecond: 600, } _, codeConstructor, _ = New(conf) ctx = context.Background() ) ``` ## 生成当前库所有表 ```go // TestGenAll 生成当前库所有表 func TestGenAll(t *testing.T) { info, err := codeConstructor.ToAllStructInfo(ctx) if err != nil { panic(err) } for i := range info { err = WriteStruct(ctx, info[i]) if err != nil { panic(err) } } time.Sleep(time.Second) } ``` ## 新增,未设置的值将使用类型默认值补充 ```go // TestInsert 新增,未设置的值将使用类型默认值补充 func TestInsert(t *testing.T) { var tb tables.TbTest tb.UserId = 199999 tb.CategoryId = 123 tb.ArticleCover = "Ar't''icl\\'\\\\'\\'eCover" tb.ArticleTitle = "ArticleTitle" tb.ArticleContent = "ArticleContent" tb.Type = 4 tb.OriginalUrl = "OriginalUrl" tb.IsTop = 1 tb.IsDelete = 0 tb.Status = 1 tb.Sortno = 99 tb.UpdateTime = time.Now() insert, pkid, err := tcode.Insert(ctx, &tb) fmt.Println(insert, pkid, err) fmt.Println(tb) } ``` ## 批量新增 ```go // TestInsertBatch 批量新增 func TestInsertBatch(t *testing.T) { var tbs []tcode.Table for i := 0; i < 1000; i++ { var tb tables.TbTest tb.UserId = int32(i) tb.UpdateTime = time.Now() tb.ArticleTitle = "测试批量新增123" tbs = append(tbs, &tb) } insert, pkid, err := tcode.InsertBatch(ctx, &tbs) fmt.Println(insert, pkid, err) } ``` ## 更新;忽略每一个空列(类型默认值进行忽略) ```go // TestUpdate 更新;忽略每一个空列(类型默认值进行忽略) func TestUpdate(t *testing.T) { var tb tables.TbTest tb.Id = 201434 tb.ArticleTitle = "测试\\'1234" update, id, err := tcode.UpdateByPk(ctx, &tb) fmt.Println(update, id, err) } ``` ## 更新:不忽略任何一列 ```go // TestUpdateNotIgnoredEveryColumn 更新:不忽略任何一列 func TestUpdateNotIgnoredEveryColumn(t *testing.T) { var tb tables.TbTest tb.Id = pkid tb.ArticleTitle = "测试1234" update, id, err := tcode.UpdateNotIgnoredEveryColumnByPk(ctx, &tb) fmt.Println(update, id, err) } ``` ## 删除 ```go // TestDelete 删除 func TestDelete(t *testing.T) { var tb tables.TbTest tb.Id = pkid affected, id, err := tcode.DeleteByPk(ctx, &tb) if err != nil { panic(err) } fmt.Println(affected, id, err) } ``` ## 查询结果映射变量 ```go // TestSelectToVar 查询结果映射变量 func TestSelectToVar(t *testing.T) { var id int err := tcode.NewSqlInfo(ctx, "SELECT id FROM tb_test WHERE id=?", pkid).ToVar(&id) if err != nil { panic(err) } fmt.Println(id) } ``` ## 查询结果映射结构体ToStruct ```go // TestSelect 查询结果映射结构体ToStruct func TestSelect(t *testing.T) { toStruct, err := tcode.Select[*tables.TbTest](ctx).AppendSQL(" WHERE id=?", pkid).ToStruct() if err != nil { panic(err) } fmt.Println(toStruct, err) } ``` ## 查询结果映射为切片 ```go // TestSelect1 查询结果映射为切片 func TestSelect1(t *testing.T) { //PossibleQueryEmptyColumn 查询的列可能有空数据(nil) //toSlice, err := tcode.Select[*tables.TbTest](ctx).PossibleQueryEmptyColumn().ToSlice(nil) toSlice, err := tcode.Select[*tables.TbTest](ctx).ToSlice(nil) if err != nil { panic(err) } slice := *toSlice for i := range slice { fmt.Println(slice[i]) } } ``` ## 没有结构体的情况下,将查询结果映射为原始表 ```go // TestSelectToRawTable 没有结构体的情况下,将查询结果映射为原始表 func TestSelectToRawTable(t *testing.T) { table, err := tcode.NewSqlInfo(ctx, "select * FROM tb_test").ToRawTable(nil) if err != nil { panic(err) } //获取行 row := table.GetRow(1) fmt.Println(row["id"]) //获取列 col := table.GetColumnByIndex(2) //col := table.GetColumnByName("列明") for i := range col { fmt.Println(col[i]) } } ``` ## 分页查询 ```go // TestPage 分页查询 func TestPage(t *testing.T) { newPage := tcode.NewPage() newPage.PageSize = 2 newPage.NextPage = 1 page, err := tcode.Select[*tables.TbTest](ctx, "id,article_title").PossibleQueryEmptyColumn().ToPage(newPage) if err != nil { panic(err) } p := *page for i := range p { fmt.Println(p[i].Id) fmt.Println(p[i].ArticleTitle) } fmt.Println(newPage) } ``` ## 自定义分页查询总记录数函数 ```go // TestPage2 分页查询;自定义查询总记录数函数 func TestPage2(t *testing.T) { newPage := tcode.NewPage() newPage.PageSize = 2 newPage.NextPage = 1 newPage.FuncCustomTotal = func(total *int) error { err := tcode.NewSqlInfo(ctx, "SELECT COUNT(*) FROM tb_test").ToVar(total) if err != nil { return err } return nil } page, err := tcode.Select[*tables.TbTest](ctx, "id,article_title").PossibleQueryEmptyColumn().ToSlice(newPage) if err != nil { panic(err) } p := *page for i := range p { fmt.Println(p[i].Id) fmt.Println(p[i].ArticleTitle) } fmt.Println(newPage) } ``` ## 查询条件,in,like ```go // TestSelect4 查询条件,in,like func TestSelect4(t *testing.T) { ids := []int32{pkid} cids := []int{186} slice, err := tcode.Select[*tables.TbTest](ctx).AppendSQL("WHERE id in (?) AND category_id IN (?) and article_title like ?", ids, cids, "%测试%").ToSlice(nil) if err != nil { panic(err) } s := *slice for i := range s { fmt.Println(s[i]) } } ``` ## 使用事务 ```go // TestTransaction 使用事务 func TestTransaction(t *testing.T) { err := tcode.Transaction(ctx, func(ctx context.Context) error { var tb tables.TbTest tb.UserId = 199999 tb.CategoryId = 123 tb.ArticleCover = "rollback" tb.ArticleTitle = "ArticleTitle" tb.ArticleContent = "ArticleContent" tb.Type = 4 tb.OriginalUrl = "OriginalUrl" tb.IsTop = 1 tb.IsDelete = 0 tb.Status = 1 tb.Sortno = 99 tb.UpdateTime = time.Now() insert, id, err := tcode.Insert(ctx, &tb) fmt.Println(insert, id, err) err2 := tcode.Transaction(ctx, func(ctx context.Context) error { var tb tables.TbTest tb.UserId = 199999 tb.CategoryId = 123 tb.ArticleCover = "commit" tb.ArticleTitle = "ArticleTitle" tb.ArticleContent = "ArticleContent" tb.Type = 4 tb.OriginalUrl = "OriginalUrl" tb.IsTop = 1 tb.IsDelete = 0 tb.Status = 1 tb.Sortno = 99 tb.UpdateTime = time.Now() insert, id, err := tcode.Insert(ctx, &tb) fmt.Println(insert, id, err) return nil }) fmt.Println(err2) insert, id, err = tcode.Insert(ctx, &tb) fmt.Println(insert, id, err) return errors.New("rollback") }) fmt.Println(err) } ``` ## 开启调试sql ```go // TestDebugSQL 开启调试sql,会将参数值拼接好的完整sql打印至控制台,用户开发阶段调试复杂sql,可直接在sql控制台执行的sql func TestDebugSQL(t *testing.T) { conf = &tcode.Config{ Dsn: "root:root@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=true&loc=Local", DriverName: "mysql", Dialect: "mysql", MaxOpenConns: 50, MaxIdleConns: 50, ConnMaxLifetimeSecond: 600, PrimaryKeyColumnName: "id", DebugSQL: true, } _, _, _ = tcode.New(conf) ids := []int32{pkid} cids := []int{186} slice, err := tcode.Select[*tables.TbTest](context.Background()).AppendSQL("WHERE id in (?) AND category_id IN (?) and article_title like ?", ids, cids, "%测试%").ToSlice(nil) if err != nil { panic(err) } s := *slice for i := range s { fmt.Println(s[i]) } } ``` ## 日志重写 ```go tcode.FuncLog = func(arbitrarily ...interface{}) { // 日志重写 } tcode.FuncSQLLog = func(ms float64, sql string, params []any) { // sql日志重写 } ``` ## 不实现Table接口进行表和结构体进行转换 ```go // Test_rawTable_ConvertStruct 转换结构体 func Test_rawTable_ConvertStruct(t *testing.T) { test1 := struct { Id int32 ArticleTitle string CreateTime time.Time UpdateTime time.Time Sortno int32 }{} table, err := NewSqlInfo(ctx, "select * FROM tb_test where id=?", 1014).ToRawTable(nil) if err != nil { fmt.Println(err) } err = Convert(table,&test1) fmt.Println(err, test1) } // Test_rawTable_Convert_Slice 转换结构体切片 func Test_rawTable_Convert_Slice(t *testing.T) { var test1 []struct { Id int32 ArticleTitle string CreateTime time.Time UpdateTime time.Time Sortno int32 } table, err := NewSqlInfo(ctx, "select * FROM tb_test where id=?", 1014).ToRawTable(nil) if err != nil { fmt.Println(err) } err = Convert(table,&test1) fmt.Println(err, test1) } ``` ## rawTable 转换基本类型切片 ```go // Test_rawTable_ConvertColIndex_Var_Slice 转换基本类型切片 func Test_rawTable_ConvertColIndex_Var_Slice(t *testing.T) { var test1 []int table, err := NewSqlInfo(ctx, "select id,user_id FROM tb_test where id=?", 1014).ToRawTable(nil) if err != nil { fmt.Println(err) } err = ConvertColIndex(table, 1, &test1) fmt.Println(err, test1) } ``` ## rawTable分页查询 ```go // Test_rawTable_Convert_Slice rawTable分页查询 func Test_rawTable_Convert_Slice_QueryPage(t *testing.T) { var test1 []struct { Id int32 ArticleTitle string CreateTime time.Time UpdateTime time.Time Sortno int32 } newPage := NewPage() table, err := NewSqlInfo(ctx, "select * FROM tb_test").ToRawTable(newPage) if err != nil { fmt.Println(err) } err = Convert(table, &test1) fmt.Println(newPage, err, test1) } ``` # 参与贡献 1. Fork 本仓库 2. 新建 Feat_master 分支 3. 提交代码 4. 新建 Pull Request