整合数据库组件

This commit is contained in:
fancl 2024-12-12 11:45:03 +08:00
commit ed42db709f
14 changed files with 429 additions and 0 deletions

60
.gitignore vendored 100644
View File

@ -0,0 +1,60 @@
bin/
.svn/
.godeps
./build
.cover/
dist
_site
_posts
*.dat
.vscode
vendor
# Go.gitignore
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
storage
.idea
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.local
.DS_Store
profile
# vim stuff
*.sw[op]
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
.vscode/*
!.vscode/extensions.json
node_modules

2
README.md 100644
View File

@ -0,0 +1,2 @@
# 模版

5
api.go 100644
View File

@ -0,0 +1,5 @@
package moto
func (svr *Server) routes() {
}

44
cmd/main.go 100644
View File

@ -0,0 +1,44 @@
package main
import (
"flag"
"fmt"
"git.nobla.cn/golang/kos"
"git.nobla.cn/golang/moto"
"git.nobla.cn/golang/moto/config"
"git.nobla.cn/golang/moto/version"
yaml "gopkg.in/yaml.v3"
"os"
)
var (
configFlag = flag.String("config", "", "Config filename")
)
func main() {
var (
buf []byte
err error
)
flag.Parse()
cfg := config.New()
if *configFlag != "" {
if buf, err = os.ReadFile(*configFlag); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
if err = yaml.Unmarshal(buf, cfg); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
}
svr := kos.Init(
kos.WithName("git.nobla.cn/golang/"+version.ProductName, version.Version),
kos.WithServer(moto.New(cfg)),
)
if err = svr.Run(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}

58
common/db/db.go 100644
View File

@ -0,0 +1,58 @@
package db
import (
"context"
"git.nobla.cn/golang/moto/config"
"git.nobla.cn/golang/rest/types"
"github.com/go-sql-driver/mysql"
mysqlDriver "gorm.io/driver/mysql"
"gorm.io/gorm"
"time"
)
var (
db *gorm.DB
)
func Init(ctx context.Context, cfg config.Database, plugins ...gorm.Plugin) (err error) {
dbCfg := &mysql.Config{
Net: "tcp",
Addr: cfg.Address,
User: cfg.Username,
Passwd: cfg.Password,
DBName: cfg.Database,
AllowNativePasswords: true,
AllowOldPasswords: true,
Collation: "utf8mb4_unicode_ci",
Loc: time.Local,
CheckConnLiveness: true,
Params: make(map[string]string),
ParseTime: true,
MaxAllowedPacket: 4 << 20,
}
dbCfg.Params["charset"] = "utf8mb4"
if db, err = gorm.Open(mysqlDriver.Open(dbCfg.FormatDSN())); err != nil {
return
}
db = db.WithContext(ctx)
for _, plugin := range plugins {
if err = db.Use(plugin); err != nil {
return
}
}
if err = db.AutoMigrate(&types.Schema{}); err != nil {
return
}
return
}
func DB() *gorm.DB {
if db == nil {
panic("database component not initialized")
}
return db
}
func WithContext(ctx context.Context) *gorm.DB {
return DB().WithContext(ctx)
}

17
config/config.go 100644
View File

@ -0,0 +1,17 @@
package config
type Database struct {
Address string `json:"address" yaml:"address"`
Username string `json:"username" yaml:"username"`
Password string `json:"password" yaml:"password"`
Database string `json:"database" yaml:"database"`
}
type Config struct {
Database Database `json:"database" yaml:"database"`
}
func New() *Config {
cfg := &Config{}
return cfg
}

View File

@ -0,0 +1,5 @@
database:
address: "192.168.9.199:3306"
username: "root"
password: "root"
database: "test2"

33
go.mod 100644
View File

@ -0,0 +1,33 @@
module git.nobla.cn/golang/moto
go 1.22.9
require (
git.nobla.cn/golang/kos v0.1.32
git.nobla.cn/golang/rest v0.0.1
github.com/go-sql-driver/mysql v1.8.1
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/mysql v1.5.7
gorm.io/gorm v1.25.12
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.23.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-runewidth v0.0.3 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/peterh/liner v1.2.2 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
)

67
go.sum 100644
View File

@ -0,0 +1,67 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
git.nobla.cn/golang/kos v0.1.32 h1:sFVCA7vKc8dPUd0cxzwExOSPX2mmMh2IuwL6cYS1pBc=
git.nobla.cn/golang/kos v0.1.32/go.mod h1:35Z070+5oB39WcVrh5DDlnVeftL/Ccmscw2MZFe9fUg=
git.nobla.cn/golang/rest v0.0.1 h1:atEF73F7NuzYGWzO4+H2qHwgtwV+omG1paEj1DJ5RN8=
git.nobla.cn/golang/rest v0.0.1/go.mod h1:tGDOul2GGJtxk6fAeu+YLpMt/Up/TsBonTkygymN/wE=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/peterh/liner v1.2.2 h1:aJ4AOodmL+JxOZZEL2u9iJf8omNRpqHc/EbrK+3mAXw=
github.com/peterh/liner v1.2.2/go.mod h1:xFwJyiKIXJZUKItq5dGHZSTBRAuG/CpeNpWLyiNRNwI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=

View File

@ -0,0 +1,18 @@
package models
import "gorm.io/gorm"
type Department struct {
ID string `json:"id" gorm:"primaryKey;size:20" comment:"ID" scenarios:"view;export"`
CreatedAt int64 `json:"created_at" gorm:"autoCreateTime" comment:"创建时间" scenarios:"list;view;export"`
UpdatedAt int64 `json:"updated_at" gorm:"autoUpdateTime" comment:"更新时间" scenarios:"list;view;export"`
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index" comment:"删除时间"`
Parent string `json:"parent" gorm:"index;size:20;not null;default:''" props:"match:exactly" comment:"归属" format:"department" scenarios:"search;list;create;update;view;export" live:"type:dropdown;url:/organize/department-types" position:"3"`
Name string `json:"name" gorm:"size:60;not null;default:''" rule:"required" comment:"名称" scenarios:"search;list;create;update;view;export" position:"2"`
Description string `json:"description" gorm:"size:500;not null;default:''" format:"textarea" comment:"备注" scenarios:"create;update;view;export"`
Position int `json:"position" gorm:"not null;default:0" comment:"排序" scenarios:""`
}
func (model *Department) TableName() string {
return "departments"
}

18
models/role.go 100644
View File

@ -0,0 +1,18 @@
package models
import "gorm.io/gorm"
type Role struct {
ID string `json:"id" gorm:"primaryKey;size:20" comment:"ID" scenarios:"view;export"`
CreatedAt int64 `json:"created_at" gorm:"autoCreateTime" comment:"创建时间" scenarios:"list;view;export"`
UpdatedAt int64 `json:"updated_at" gorm:"autoUpdateTime" comment:"更新时间" scenarios:"list;view;export"`
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index" comment:"删除时间"`
Name string `json:"name" gorm:"size:60;not null;default:''" rule:"required" comment:"名称" scenarios:"search;list;create;update;view;export" position:"2"`
Description string `json:"description" gorm:"size:500;not null;default:''" format:"textarea" comment:"备注" scenarios:"create;update;view;export"`
Permissions string `json:"permissions" gorm:"size:10240;not null;default:''" comment:"权限" scenarios:"create;update"`
Position int `json:"position" gorm:"not null;default:0" comment:"排序" scenarios:""`
}
func (model *Role) TableName() string {
return "roles"
}

27
models/user.go 100644
View File

@ -0,0 +1,27 @@
package models
import (
"gorm.io/gorm"
)
type User struct {
ID string `json:"id" gorm:"primaryKey;size:20" comment:"ID" scenarios:"view;export"`
CreatedAt int64 `json:"created_at,omitempty" gorm:"autoCreateTime" comment:"创建时间" scenarios:"view;export"`
UpdatedAt int64 `json:"updated_at,omitempty" gorm:"autoUpdateTime" comment:"更新时间" scenarios:"view;export"`
DeletedAt gorm.DeletedAt `json:"deleted_at,omitempty" gorm:"index" comment:"删除时间"`
UID string `json:"uid" gorm:"column:uid;index;size:20;not null;default:''" rule:"required;unique;regexp:^[a-zA-Z0-9]{3,8}$;" props:"readonly:update" comment:"账号" scenarios:"search;list;create;view;export"`
Department string `json:"department,omitempty" gorm:"index;size:20;not null;default:''" rule:"required" comment:"部门" scenarios:"search;list;create;update;view;export" live:"type:dropdown;url:/organize/department-types"`
Role string `json:"role,omitempty" gorm:"index;size:20;not null;default:''" rule:"required" comment:"角色" scenarios:"search;list;create;update;view;export" live:"type:dropdown;url:/organize/role-types"`
Username string `json:"username" gorm:"index;size:36;not null;default:''" rule:"required" comment:"用户名" scenarios:"search;list;create;update;view;export"`
Tag string `json:"tag" gorm:"index;size:60;not null;default:''" comment:"标签" dropdown:"created;filterable;default_first" live:"type:dropdown;url:/organize/user-tags" scenarios:"list;search;create;update;view;export"`
Password string `json:"password,omitempty" gorm:"size:60;not null;default:''" rule:"required" comment:"密码" scenarios:"create"`
Avatar string `json:"avatar" gorm:"size:1024;not null;default:''" comment:"头像" scenarios:"view"`
Email string `json:"email" gorm:"size:120;not null;default:''" comment:"邮箱" scenarios:"search;list;create;update;view;export"`
Phone string `json:"phone" gorm:"size:36;not null;default:''" comment:"手机" scenarios:"search;list;create;update;view;export"`
Gender string `json:"gender,omitempty" gorm:"default:man" comment:"性别" scenarios:"list;create;update;view;export" enum:"man:男;woman:女;other:其他"`
Description string `json:"description,omitempty" gorm:"size:250;not null;default:''" format:"textarea" comment:"备注" scenarios:"create;update;view;export"`
}
func (model *User) TableName() string {
return "users"
}

69
server.go 100644
View File

@ -0,0 +1,69 @@
package moto
import (
"context"
"git.nobla.cn/golang/kos"
httpkg "git.nobla.cn/golang/kos/entry/http"
"git.nobla.cn/golang/moto/common/db"
"git.nobla.cn/golang/moto/config"
"git.nobla.cn/golang/moto/models"
"git.nobla.cn/golang/moto/version"
"git.nobla.cn/golang/rest"
"io"
"net/http"
)
type Server struct {
cfg *config.Config
ctx context.Context
cancelFunc context.CancelCauseFunc
}
func (svr *Server) prepare() (err error) {
if err = db.Init(svr.ctx, svr.cfg.Database); err != nil {
return
}
values := []any{
&models.User{},
&models.Role{},
&models.Department{},
}
for _, item := range values {
if err = db.DB().AutoMigrate(item); err != nil {
return
}
if err = rest.AutoMigrate(svr.ctx, db.DB(), item, rest.WithoutDomain(), rest.WithModuleName(version.ProductName)); err != nil {
return
}
}
rest.SetHttpRouter(svr)
return
}
func (svr *Server) Handle(method string, uri string, handler http.HandlerFunc) {
kos.Http().Handle(method, uri, func(ctx *httpkg.Context) (err error) {
handler(ctx.Response(), ctx.Request())
return
})
}
func (svr *Server) Start(ctx context.Context) (err error) {
svr.ctx, svr.cancelFunc = context.WithCancelCause(ctx)
if err = svr.prepare(); err != nil {
return
}
svr.routes()
return
}
func (svr *Server) Stop() (err error) {
svr.cancelFunc(io.ErrClosedPipe)
return
}
func New(cfg *config.Config) *Server {
svr := &Server{
cfg: cfg,
}
return svr
}

View File

@ -0,0 +1,6 @@
package version
var (
ProductName = "moto"
Version = "0.0.1"
)