Model
package model
import (
"context"
"errors"
"fmt"
"time"
"github.com/asjard/asjard/core/bootstrap"
"github.com/asjard/asjard/core/logger"
"github.com/asjard/asjard/core/status"
"github.com/asjard/asjard/pkg/cache"
"github.com/asjard/asjard/pkg/protobuf/requestpb"
"github.com/asjard/asjard/pkg/stores"
"github.com/asjard/asjard/pkg/stores/xgorm"
pb "github.com/asjard/examples/protobuf/mysqlpb"
"google.golang.org/grpc/codes"
"gorm.io/gorm"
)
type ExampleTable struct {
Id int64 `gorm:"column:id;type:INT(20);primaryKey;autoIncrement"`
Name string `gorm:"column:name;type:VARCHAR(20);uniqueIndex"`
Age uint32 `gorm:"column:age;type:INT"`
CreatedAt time.Time
UpdatedAt time.Time
}
type ExampleModel struct {
stores.Model
*ExampleTable
kvCache *cache.CacheRedis
}
// TableName 数据库表名
func (ExampleTable) TableName() string {
return "example_table"
}
// ModelName 全局唯一的表名
func (ExampleTable) ModelName() string {
return "example_database_example_table"
}
// NewExampleModel 模型初始化
// 用XXXModel去复写XXXTable的方法
func NewExampleModel() *ExampleModel {
exampleModel := &ExampleModel{
ExampleTable: &ExampleTable{},
}
bootstrap.AddBootstrap(exampleModel)
return exampleModel
}
// Bootstrap 缓存初始化
func (model *ExampleModel) Bootstrap() (err error) {
localCache, err := cache.NewLocalCache(model.ExampleTable)
if err != nil {
return err
}
model.kvCache, err = cache.NewRedisKeyValueCache(model.ExampleTable,
cache.WithLocalCache(localCache))
if err != nil {
return err
}
return nil
}
// Shutdown .
func (model *ExampleModel) Shutdown() {}
func (model *ExampleModel) Create(ctx context.Context, in *pb.CreateOrUpdateReq) error {
// 需要删除删除缓存
// 创建需要提前分配缓存Key
// 如果是按照主键ID缓存的,提前生成主键ID,创建记录使用提前生成的主键ID创建记录
if err := model.SetData(ctx,
model.kvCache.WithGroup(model.searchGroup()).WithKey(model.getCacheKey(in.Name)),
func() error {
return model.ExampleTable.Create(ctx, in)
}); err != nil {
return err
}
return nil
}
func (model *ExampleModel) Update(ctx context.Context, in *pb.CreateOrUpdateReq) (*pb.ExampleInfo, error) {
if err := model.SetData(ctx,
model.kvCache.WithGroup(model.searchGroup()).WithKey(model.getCacheKey(in.Name)),
func() error {
if _, err := model.ExampleTable.Update(ctx, in); err != nil {
return err
}
return nil
}); err != nil {
return nil, err
}
return model.Get(ctx, &pb.ReqWithName{Name: in.Name})
}
func (model *ExampleModel) Get(ctx context.Context, in *pb.ReqWithName) (*pb.ExampleInfo, error) {
var resp pb.ExampleInfo
if err := model.GetData(ctx,
&resp,
model.kvCache.WithKey(model.getCacheKey(in.Name)),
func() (any, error) {
return model.ExampleTable.Get(ctx, in)
}); err != nil || resp.Id == 0 {
return nil, status.Errorf(codes.NotFound, "record not found")
}
return &resp, nil
}
func (model *ExampleModel) Search(ctx context.Context, in *pb.SearchReq) (*pb.ExampleList, error) {
var result pb.ExampleList
if err := model.GetData(ctx, &result,
model.kvCache.WithKey(model.searchCacheKey(in)).WithGroup(model.searchGroup()),
func() (any, error) {
return model.ExampleTable.Search(ctx, in)
}); err != nil {
return nil, err
}
return &result, nil
}
func (model *ExampleModel) Del(ctx context.Context, in *pb.ReqWithName) error {
return model.SetData(ctx,
model.kvCache.WithKey(model.getCacheKey(in.Name)).WithGroup(model.searchGroup()),
func() error {
return model.ExampleTable.Del(ctx, in)
})
}
func (model *ExampleModel) searchGroup() string {
return "search"
}
func (model *ExampleModel) searchCacheKey(in *pb.SearchReq) string {
return fmt.Sprintf("search:%d:%d:%s", in.Page, in.Size, in.Sort)
}
func (model *ExampleModel) getCacheKey(name string) string {
return fmt.Sprintf("info:%s", name)
}
func (t ExampleTable) Create(ctx context.Context, in *pb.CreateOrUpdateReq) error {
db, err := xgorm.DB(ctx)
if err != nil {
return err
}
if err := db.Where("name=?", in.Name).First(&ExampleTable{}).Error; err == nil {
return status.Errorf(codes.AlreadyExists, "record %s already exist", in.Name)
}
if err := db.Create(&ExampleTable{
Name: in.Name,
Age: in.Age,
}).Error; err != nil {
logger.Error("create fail", "name", in.Name, "err", err)
return status.InternalServerError()
}
return nil
}
func (t ExampleTable) Update(ctx context.Context, in *pb.CreateOrUpdateReq) (*pb.ExampleInfo, error) {
db, err := xgorm.DB(ctx)
if err != nil {
return nil, err
}
if _, err := t.Get(ctx, &pb.ReqWithName{Name: in.Name}); err != nil {
return nil, err
}
if err := db.Model(&ExampleTable{}).Where("name=?", in.Name).Updates(&ExampleTable{
Name: in.Name,
Age: in.Age,
}).Error; err != nil {
logger.Error("update record fail", "name", in.Name, "err", err)
return nil, status.InternalServerError()
}
return t.Get(ctx, &pb.ReqWithName{Name: in.Name})
}
func (t ExampleTable) Get(ctx context.Context, in *pb.ReqWithName) (*pb.ExampleInfo, error) {
db, err := xgorm.DB(ctx)
if err != nil {
return nil, err
}
var record ExampleTable
if err := db.Where("name=?", in.Name).First(&record).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, status.Error(codes.NotFound, "record not found")
}
logger.Error("get record fail", "name", in.Name, "err", err)
return nil, status.InternalServerError()
}
return record.info(), nil
}
func (t ExampleTable) Search(ctx context.Context, in *pb.SearchReq) (*pb.ExampleList, error) {
db, err := xgorm.DB(ctx)
if err != nil {
return nil, err
}
var total int64
db.Model(&ExampleTable{}).Count(&total)
records := make([]ExampleTable, 0, in.Size)
db.Scopes(requestpb.ReqWithPageGormScope(in.Page, in.Size, in.Sort)).Find(&records)
exampleInfos := make([]*pb.ExampleInfo, 0, in.Size)
for _, record := range records {
exampleInfos = append(exampleInfos, record.info())
}
return &pb.ExampleList{
Total: int32(total),
List: exampleInfos,
}, nil
}
func (t ExampleTable) Del(ctx context.Context, in *pb.ReqWithName) error {
db, err := xgorm.DB(ctx)
if err != nil {
return err
}
if err := db.Where("name=?", in.Name).Delete(&ExampleTable{}).Error; err != nil {
logger.Error("delete record fail", "name", in.Name, "err", err)
return status.InternalServerError()
}
return nil
}
func (t ExampleTable) info() *pb.ExampleInfo {
return &pb.ExampleInfo{
Id: t.Id,
Name: t.Name,
Age: t.Age,
CreatedAt: t.CreatedAt.Format(time.RFC3339),
UpdatedAt: t.UpdatedAt.Format(time.RFC3339),
}
}
最后更新于