Skip to content

dobyte/gorm-dao-generator

Repository files navigation

gorm-dao-generator

中文文档

1.Introduction

gorm-dao-generator is a tool for automatically generating Mysql Data Access Object.

2.Advantage

  • Provides a unified generation scheme for database fields, avoiding the problem of database fields that can be seen everywhere in business codes.

  • Provides various database operation interfaces including Insert, Delete, Update, Count, Sum, Avg, First, Last, FindOne, FindMany, etc.

  • Provides the ability to expand the database operation interface.

  • Provides two package solutions: subcontracting and non-subcontracting.

  • Supports customization of directory and file name styles.

3.Download and install

go env -w GOSUMDB=off
go install github.com/dobyte/gorm-dao-generator@latest
go env -w GOSUMDB=on

4.Usage

Usage of gorm-dao-generator:
        gorm-dao-generator [flags] -model-dir=. -model-names=M[:t],M[:t] -dao-dir=./dao
For more information, see:
        https://github.com/dobyte/gorm-dao-generator
Flags:
  -dao-dir string
        specify the output directory of dao files; must be set
  -dao-pkg-path string
        specify the package path corresponding to the output directory of the dao files; automatically generated by default
  -file-style string
        specify the generation style for file; options: kebab | underscore | lower | camel | pascal; default is underscore (default "underscore")
  -model-dir string
        specify the model directory; must be set
  -model-names string
		specify one or more modelName[:tableName] pairs; must be set
  -model-pkg-alias string
        specify a model package alias; default no alias
  -model-pkg-path string
        specify the package path corresponding to the model directory; automatically calculated by default
  -sub-pkg-enable
        specify whether to enable sub-pkg; default disable
  -sub-pkg-style string
        specify the generation style for sub-pkg; options: kebab | underscore | lower | camel | pascal; default is kebab (default "kebab")

5.Example

5-1.Create model

File Location: example/model/mail.go

package model

import (
	"time"
)

//go:generate gorm-dao-generator -model-dir=. -model-names=Mail -dao-dir=../dao/
type Mail struct {
	ID       int       `gorm:"column:id"`        // 邮件ID
	Title    string    `gorm:"column:title"`     // 邮件标题
	Content  string    `gorm:"column:content"`   // 邮件内容
	Sender   int64     `gorm:"column:sender"`    // 邮件发送者
	Receiver int64     `gorm:"column:receiver"`  // 邮件接受者
	Status   int       `gorm:"column:status"`    // 邮件状态
	SendTime time.Time `gorm:"column:send_time"` // 发送时间
}
5-2.Generate dao files
go generate ./...
5-3.Generated dao file example

File Location: example/dao/internal/mail.go

// --------------------------------------------------------------------------------------------
// The following code is automatically generated by the gorm-dao-generator tool.
// Please do not modify this code manually to avoid being overwritten in the next generation. 
// For more tool details, please click the link to view https://github.com/dobyte/gorm-dao-generator
// --------------------------------------------------------------------------------------------

package internal

import (
	"context"
	"errors"
	"fmt"
	modelpkg "github.com/dobyte/gorm-dao-generator/example/model"
	"gorm.io/gorm"
	"strconv"
	"strings"
)

type MailOrderBy struct {
	Column string	
	Order  string
}

type MailFilterFunc func(cols *MailColumns) interface{}
type MailUpdateFunc func(cols *MailColumns) interface{}
type MailColumnFunc func(cols *MailColumns) []string
type MailOrderFunc func(cols *MailColumns) []MailOrderBy

type Mail struct {
	Columns   *MailColumns
	Database  *gorm.DB
	TableName string
}

type MailColumns struct {
	ID       string // 邮件ID
	Title    string // 邮件标题
	Content  string // 邮件内容
	Sender   string // 邮件发送者
	Receiver string // 邮件接受者
	Status   string // 邮件状态
	SendTime string // 发送时间
}

var mailColumns = &MailColumns{
	ID:       "id",        // 邮件ID
	Title:    "title",     // 邮件标题
	Content:  "content",   // 邮件内容
	Sender:   "sender",    // 邮件发送者
	Receiver: "receiver",  // 邮件接受者
	Status:   "status",    // 邮件状态
	SendTime: "send_time", // 发送时间
}

func NewMail(db *gorm.DB) *Mail {
	dao := &Mail{}
	dao.Columns = mailColumns
	dao.TableName = "mail"
	dao.Database = db

	return dao
}

// New create a new instance and return
func (dao *Mail) New(tx *gorm.DB) *Mail {
	d := &Mail{}
	d.Columns = dao.Columns
	d.TableName = dao.TableName
	d.Database = tx

	return d
}

// Table create a new table db instance
func (dao *Mail) Table(ctx context.Context) *gorm.DB {
	return dao.Database.Model(&modelpkg.Mail{}).Table(dao.TableName).WithContext(ctx)
}

// Insert executes an insert command to insert multiple documents into the collection.
func (dao *Mail) Insert(ctx context.Context, models ...*modelpkg.Mail) (int64, error) {
	if len(models) == 0 {
		return 0, errors.New("models is empty")
	}

	var rst *gorm.DB

	if len(models) == 1 {
		rst = dao.Table(ctx).Create(models[0])
	} else {
		rst = dao.Table(ctx).Create(models)
	}

	return rst.RowsAffected, rst.Error
}

// Delete executes a delete command to delete at most one document from the collection.
func (dao *Mail) Delete(ctx context.Context, filterFunc ...MailFilterFunc) (int64, error) {
	db := dao.Table(ctx)

	if len(filterFunc) > 0 && filterFunc[0] != nil {
		db = db.Where(filterFunc[0](dao.Columns))
	}

	rst := db.Delete(&modelpkg.Mail{})

	return rst.RowsAffected, rst.Error
}

// Update executes an update command to update documents in the collection.
func (dao *Mail) Update(ctx context.Context, filterFunc MailFilterFunc, updateFunc MailUpdateFunc, columnFunc ...MailColumnFunc) (int64, error) {
	db := dao.Table(ctx)

	if filterFunc != nil {
		db = db.Where(filterFunc(dao.Columns))
	}

	if len(columnFunc) > 0 && columnFunc[0] != nil {
		db = db.Select(columnFunc[0](dao.Columns))
	}

	if updateFunc != nil {
		rst := db.Updates(updateFunc(dao.Columns))

		return rst.RowsAffected, rst.Error
	}

	return 0, nil
}

// Count returns the number of documents in the collection.
func (dao *Mail) Count(ctx context.Context, filterFunc ...MailFilterFunc) (count int64, err error) {
    db := dao.Table(ctx)

	if len(filterFunc) > 0 && filterFunc[0] != nil {
		db = db.Where(filterFunc[0](dao.Columns))
	}

	err = db.Count(&count).Error

	return
}

// Sum returns the sum of the given field.
func (dao *Mail) Sum(ctx context.Context, columnFunc MailColumnFunc, filterFunc ...MailFilterFunc) (sums []float64, err error) {
	columns := columnFunc(dao.Columns)
	if len(columns) == 0 {
		return
	}

	fields := make([]string, len(columns))
	for i, column := range columns {
		fields[i] = fmt.Sprintf("COALESCE(SUM(%s), 0) as `sum_%d`", column, i)
	}

	db := dao.Table(ctx).Select(strings.Join(fields, ","))

	if len(filterFunc) > 0 && filterFunc[0] != nil {
		db = db.Where(filterFunc[0](dao.Columns))
	}

	rst := make(map[string]interface{}, len(columns))

	if err = db.Scan(&rst).Error; err != nil {
		return
	}

	for i := range columns {
		val, _ := rst[fmt.Sprintf("sum_%d", i)]
		sum, _ := strconv.ParseFloat(val.(string), 64)
		sums = append(sums, sum)
	}

	return
}

// Avg returns the avg of the given field.
func (dao *Mail) Avg(ctx context.Context, columnFunc MailColumnFunc, filterFunc ...MailFilterFunc) (avgs []float64, err error) {
	columns := columnFunc(dao.Columns)
	if len(columns) == 0 {
		return
	}

	fields := make([]string, len(columns))
	for i, column := range columns {
		fields[i] = fmt.Sprintf("COALESCE(AVG(%s), 0) as `avg_%d`", column, i)
	}

	db := dao.Table(ctx).Select(strings.Join(fields, ","))

	if len(filterFunc) > 0 && filterFunc[0] != nil {
		db = db.Where(filterFunc[0](dao.Columns))
	}

	rst := make(map[string]interface{}, len(columns))

	if err = db.Scan(&rst).Error; err != nil {
		return
	}

	for i := range columns {
		val, _ := rst[fmt.Sprintf("avg_%d", i)]
		avg, _ := strconv.ParseFloat(val.(string), 64)
		avgs = append(avgs, avg)
	}

	return
}

// First executes a first command and returns a model for one record in the table.
func (dao *Mail) First(ctx context.Context, filterFunc MailFilterFunc, columnFunc ...MailColumnFunc) (*modelpkg.Mail, error) {
	var (
		model = &modelpkg.Mail{}
		db    = dao.Table(ctx)
	)

	if filterFunc != nil {
		db = db.Where(filterFunc(dao.Columns))
	}

	if len(columnFunc) > 0 && columnFunc[0] != nil {
		columns := columnFunc[0](dao.Columns)

		if len(columns) > 0 {
			db = db.Select(columns)
		}
	}

	if rst := db.First(model); rst.Error != nil {
		if errors.Is(rst.Error, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, rst.Error
	}

	return model, nil
}

// Last executes a last command and returns a model for one record in the table.
func (dao *Mail) Last(ctx context.Context, filterFunc MailFilterFunc, columnFunc ...MailColumnFunc) (*modelpkg.Mail, error) {
	var (
		model = &modelpkg.Mail{}
		db    = dao.Table(ctx)
	)

	if filterFunc != nil {
		db = db.Where(filterFunc(dao.Columns))
	}

	if len(columnFunc) > 0 && columnFunc[0] != nil {
		columns := columnFunc[0](dao.Columns)

		if len(columns) > 0 {
			db = db.Select(columns)
		}
	}

	if rst := db.Last(model); rst.Error != nil {
		if errors.Is(rst.Error, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, rst.Error
	}

	return model, nil
}

// FindOne executes a take command and returns a model for one record in the table.
func (dao *Mail) FindOne(ctx context.Context, filterFunc MailFilterFunc, columnFunc ...MailColumnFunc) (*modelpkg.Mail, error) {
	var (
		model = &modelpkg.Mail{}
		db    = dao.Table(ctx)
	)

	if filterFunc != nil {
		db = db.Where(filterFunc(dao.Columns))
	}

	if len(columnFunc) > 0 && columnFunc[0] != nil {
		columns := columnFunc[0](dao.Columns)

		if len(columns) > 0 {
			db = db.Select(columns)
		}
	}

	if rst := db.Take(model); rst.Error != nil {
		if errors.Is(rst.Error, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, rst.Error
	}

	return model, nil
}

// FindMany executes a find command and returns many models the matching documents in the collection.
func (dao *Mail) FindMany(ctx context.Context, filterFunc MailFilterFunc, columnFunc MailColumnFunc, orderFunc MailOrderFunc, limitAndOffset ...int) ([]*modelpkg.Mail, error) {
	var (
		models = make([]*modelpkg.Mail, 0)
		db     = dao.Table(ctx)
	)

	if filterFunc != nil {
		db = db.Where(filterFunc(dao.Columns))
	}

	if columnFunc != nil {
		columns := columnFunc(dao.Columns)

		if len(columns) > 0 {
			db = db.Select(columns)
		}
	}

	if orderFunc != nil {
		orders := orderFunc(dao.Columns)

		for _, order := range orders {
			db = db.Order(fmt.Sprintf("%s %s", order.Column, order.Order))
		}
	}

	if len(limitAndOffset) > 0 {
		db = db.Limit(limitAndOffset[0])
	}

	if len(limitAndOffset) > 1 {
		db = db.Offset(limitAndOffset[1])
	}

	rst := db.Scan(&models)

	if rst.Error != nil {
		if errors.Is(rst.Error, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, rst.Error
	}

	return models, nil
}

File Location: example/dao/mail.go

package dao

import (
	"github.com/dobyte/gorm-dao-generator/example/dao/internal"
	"gorm.io/gorm"
)

type (
	MailColumns = internal.MailColumns
	MailOrderBy = internal.MailOrderBy
)

type Mail struct {
	*internal.Mail
}

func NewMail(db *gorm.DB) *Mail {
	return &Mail{Mail: internal.NewMail(db)}
}
5-4.Use the generated dao file

File Location: example/main.go

package main

import (
	"context"
	"github.com/dobyte/gorm-dao-generator/example/dao"
	"github.com/dobyte/gorm-dao-generator/example/model"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"log"
	"time"
)

func main() {
	dsn := "root:123456@tcp(127.0.0.1:3306)/game?charset=utf8mb4&parseTime=True&loc=Local"

	db, err := gorm.Open(mysql.New(mysql.Config{
		DSN: dsn,
	}))
	if err != nil {
		log.Fatalf("connect mysql server failed: %v", err)
	}

	mailDao := dao.NewMail(db)
	baseCtx := context.Background()

	_, err = mailDao.Insert(baseCtx, &model.Mail{
		Title:    "gorm-dao-generator introduction",
		Content:  "The gorm-dao-generator is a tool for automatically generating Mysql Data Access Object.",
		Sender:   1,
		Receiver: 2,
		Status:   1,
		SendTime: time.Now(),
	})
	if err != nil {
		log.Fatalf("failed to insert into mysql database: %v", err)
	}

	mail, err := mailDao.FindOne(baseCtx, func(cols *dao.MailColumns) interface{} {
		return map[string]interface{}{
			cols.Receiver: 2,
		}
	})
	if err != nil {
		log.Fatalf("failed to find a row of data from mysql database: %v", err)
	}

	log.Printf("%+v", mail)
}
5-5.Run result:
$ go run main.go
$ 2025/05/14 20:28:41 &{ID:1 Title:gorm-dao-generator introduction Content:The gorm-dao-generator is a tool for automatically generating Mysql Data Access Object. Sender:1 Receiver:2 Status:1 SendTime:2025-05-14 20:28:42 +0800 CST}

About

A dao file generation tool based on gorm library

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages