作者 yangfu

feat: flush / loaddata

正在显示 69 个修改的文件 包含 2595 行增加202 行删除
... ... @@ -26,4 +26,5 @@ _testmain.go
app.log
go.sum
lastupdate.tmp
\ No newline at end of file
lastupdate.tmp
*.log
\ No newline at end of file
... ...
... ... @@ -69,14 +69,12 @@
"data": {
"dataFields": [
{
"index": 1,
"name": "产品名称",
"Type": "string"
"type": "string"
},
{
"index": 2,
"name": "产品数量",
"Type": "number"
"type": "int"
}
],
"dataRows": [
... ...
version: v1
kind: HttpApi
metadata:
service: log
path: /logs
endpoints:
- method: createLog
route:
post: /
- method: updateLog
route:
put: /{logId}
- method: getLog
route:
get: /{logId}
- method: removeLog
route:
delete: /{logId}
- method: listLog
route:
get: /
params:
- name: offset
- name: limit
- method: searchLog
route:
post: /search
... ...
version: v1
kind: Method
metadata:
name: createLog
type: command
description: 创建日志服务
payload:
- ref: objectName
required: true
- ref: objectType
required: true
- ref: operationType
required: true
- ref: content
required: true
- ref: operatorName
required: true
result:
- name: log
type:
schema: log
required: true
... ...
version: v1
kind: Method
metadata:
name: getLog
type: query
description: 返回日志服务
payload:
- ref: logId
required: true
result:
- name: log
type:
schema: log
required: true
... ...
version: v1
kind: Method
metadata:
name: listLog
type: query
description: 返回日志服务列表
payload:
- ref: offset
required: true
- ref: limit
required: true
result:
- ref: count
required: true
- name: logs
type:
array: log
required: true
... ...
version: v1
kind: Method
metadata:
name: removeLog
type: command
description: 移除日志服务
payload:
- ref: logId
required: true
result:
- name: log
type:
schema: log
required: true
... ...
version: v1
kind: Method
metadata:
name: searchLog
type: command
description: 搜索日志
payload:
- ref: content
required: false
result:
- name: log
type:
schema: log
required: true
... ...
version: v1
kind: Method
metadata:
name: updateLog
type: command
description: 更新日志服务
payload:
- ref: logId
required: true
result:
- name: log
type:
schema: log
required: true
... ...
version: v1
kind: Service
metadata:
name: log
description: 日志服务
... ...
... ... @@ -3,15 +3,14 @@ module gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion
go 1.16
require (
github.com/Shopify/sarama v1.25.0
github.com/ajg/form v1.5.1 // indirect
github.com/beego/beego/v2 v2.0.1
github.com/bwmarrin/snowflake v0.3.0
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/gavv/httpexpect v2.0.0+incompatible
github.com/go-pg/pg/v10 v10.9.0
github.com/go-redis/redis v6.15.9+incompatible // indirect
github.com/go-redis/redis/v7 v7.4.1 // indirect
github.com/go-redis/redis v6.15.9+incompatible
github.com/golang/snappy v0.0.3 // indirect
github.com/google/go-cmp v0.5.6 // indirect
github.com/google/go-querystring v1.1.0 // indirect
... ... @@ -22,13 +21,16 @@ require (
github.com/onsi/ginkgo v1.15.2
github.com/onsi/gomega v1.11.0
github.com/sergi/go-diff v1.2.0 // indirect
github.com/shopspring/decimal v1.2.0
github.com/smartystreets/goconvey v1.7.2 // indirect
github.com/stretchr/testify v1.7.0
github.com/valyala/fasthttp v1.38.0 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect
github.com/yudai/gojsondiff v1.0.0 // indirect
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
github.com/yudai/pp v2.0.1+incompatible // indirect
golang.org/x/text v0.3.7
)
replace github.com/linmadan/egglib-go v0.0.0-20210313060205-8b5e456b11f7 => github.com/tiptok/egglib-go v0.0.0-20220421085958-9682d0ac42c1
... ...
... ... @@ -4,12 +4,12 @@ import (
"fmt"
"github.com/beego/beego/v2/server/web"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/constant"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/pg"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/redis"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/log"
"time"
_ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/constant"
_ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/pg"
_ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/redis"
_ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/log"
_ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/port/beego"
... ... @@ -24,6 +24,7 @@ func main() {
log.InitLogHook(constant.ENABLE_KAFKA_LOG, true)
redis.InitRedis()
pg.Init()
time.Sleep(time.Second)
log.Logger.Info("server start!")
... ...
package factory
import (
"github.com/linmadan/egglib-go/core/application"
"github.com/linmadan/egglib-go/transaction/pg"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/domainService"
)
func FastLog(transactionContext application.TransactionContext, logType domain.LogType, sourceId int, logEntry domainService.Log) error {
logService, _ := domainService.NewPGLogService(transactionContext.(*pg.TransactionContext))
return logService.Log(logType, sourceId, logEntry)
}
func CreateLoadDataTableService(transactionContext application.TransactionContext) (domain.LoadDataTableService, error) {
return domainService.NewLoadDataTableService(transactionContext.(*pg.TransactionContext))
}
func CreateFlushDataTableService(transactionContext application.TransactionContext) (domain.FlushDataTableService, error) {
return domainService.NewFlushDataTableService(transactionContext.(*pg.TransactionContext))
}
func CreateDeleteFileService(transactionContext application.TransactionContext) (domain.DeleteFileService, error) {
return domainService.NewDeleteFileService(transactionContext.(*pg.TransactionContext))
}
func CreateGenerateMainTableService(transactionContext application.TransactionContext) (domain.GenerateMainTableService, error) {
return domainService.NewGenerateMainTableService(transactionContext.(*pg.TransactionContext))
}
... ...
package factory
import (
"github.com/linmadan/egglib-go/core/application"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
)
// FastPgFile 快速返回文件对象
//
// transactionContext 事务
// id 对象唯一标识
func FastPgFile(transactionContext application.TransactionContext, id int) (domain.FileRepository, *domain.File, error) {
var rep domain.FileRepository
var mod *domain.File
var err error
if value, err := CreateFileRepository(map[string]interface{}{
"transactionContext": transactionContext,
}); err != nil {
return nil, nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
rep = value
}
if id > 0 {
if mod, err = rep.FindOne(map[string]interface{}{"fileId": id}); err != nil {
if err == domain.ErrorNotFound {
return nil, nil, application.ThrowError(application.RES_NO_FIND_ERROR, "该文件不存在")
}
return nil, nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
}
//if err = fastPgDataAuth(transactionContext, mod, options...); err != nil {
// return nil, nil, err
//}
return rep, mod, err
}
// FastPgTable 快速返回表格对象
//
// transactionContext 事务
// id 对象唯一标识
func FastPgTable(transactionContext application.TransactionContext, id int) (domain.TableRepository, *domain.Table, error) {
var rep domain.TableRepository
var mod *domain.Table
var err error
if value, err := CreateTableRepository(map[string]interface{}{
"transactionContext": transactionContext,
}); err != nil {
return nil, nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
rep = value
}
if id > 0 {
if mod, err = rep.FindOne(map[string]interface{}{"tableId": id}); err != nil {
if err == domain.ErrorNotFound {
return nil, nil, application.ThrowError(application.RES_NO_FIND_ERROR, "该表格不存在")
}
return nil, nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
}
return rep, mod, err
}
... ...
... ... @@ -2,6 +2,8 @@ package command
import (
"fmt"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
"path/filepath"
"reflect"
"strings"
... ... @@ -18,7 +20,11 @@ type CreateFileCommand struct {
}
func (createFileCommand *CreateFileCommand) Valid(validation *validation.Validation) {
ext := filepath.Ext(createFileCommand.Name)
if !(ext == domain.XLS || ext == domain.XLSX) {
validation.Error(fmt.Sprintf("仅支持文件格式 xls 、 xlsx"))
return
}
}
func (createFileCommand *CreateFileCommand) ValidateCommand() error {
... ...
... ... @@ -2,6 +2,7 @@ package command
import (
"fmt"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/file/dto"
"reflect"
"strings"
... ... @@ -11,10 +12,14 @@ import (
type FlushDataTableCommand struct {
// 文件ID
FileId int `cname:"文件ID" json:"fileId" valid:"Required"`
// 记录数
RowCount int `cname:"记录数" json:"rowCount" valid:"Required"`
// 数据列
DataFields []*dto.Field `cname:"数据列" json:"dataFields" valid:"Required"`
}
func (flushDataTableCommand *FlushDataTableCommand) Valid(validation *validation.Validation) {
validation.SetError("CustomValid", "未实现的自定义认证")
}
func (flushDataTableCommand *FlushDataTableCommand) ValidateCommand() error {
... ...
... ... @@ -11,10 +11,12 @@ import (
type GenerateMainTableCommand struct {
// 文件ID
FileId int `cname:"文件ID" json:"fileId" valid:"Required"`
// 表名
TableName string `cname:"表名" json:"tableName" valid:"Required"`
}
func (generateMainTableCommand *GenerateMainTableCommand) Valid(validation *validation.Validation) {
validation.SetError("CustomValid", "未实现的自定义认证")
}
func (generateMainTableCommand *GenerateMainTableCommand) ValidateCommand() error {
... ...
... ... @@ -11,6 +11,10 @@ import (
type LoadDataTableCommand struct {
// 文件ID
FileId int `cname:"文件ID" json:"fileId" valid:"Required"`
// 页号
PageNumber int `cname:"页号" json:"pageNumber"`
// 页号
PageSize int `cname:"数量" json:"pageSize"`
}
func (loadDataTableCommand *LoadDataTableCommand) Valid(validation *validation.Validation) {
... ...
package dto
import "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
type DataTableDto struct {
FileId int `json:"fileId"`
DataFields []*Field `json:"dataFields"`
DataRows [][]interface{} `json:"dataRows"`
Total int `json:"total"`
... ... @@ -10,11 +13,11 @@ type DataTableDto struct {
type Field struct {
// 索引序号
Index int `json:"index"`
// Index int `json:"index"`
// 名称
Name string `json:"name"`
// 对应数据库类型
Type string `json:"Type"`
Type string `json:"type"`
}
type InValidCell struct {
... ... @@ -23,18 +26,18 @@ type InValidCell struct {
Error string `json:"error"`
}
func NewDataTableDtoDemo() DataTableDto {
func NewDataTableDtoDemo(fileId int) DataTableDto {
return DataTableDto{
DataFields: []*Field{
{
Index: 1,
Name: "产品名称",
Type: "string",
//Index: 1,
Name: "产品名称",
Type: domain.String.ToString(),
},
{
Index: 2,
Name: "产品数量",
Type: "number",
//Index: 2,
Name: "产品数量",
Type: domain.Int.ToString(),
},
},
DataRows: [][]interface{}{
... ... @@ -52,5 +55,6 @@ func NewDataTableDtoDemo() DataTableDto {
},
PageNumber: 1,
Total: 100,
FileId: fileId,
}
}
... ...
package dto
import (
"github.com/linmadan/egglib-go/utils/xtime"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
)
type FileDto struct {
// 文件ID
FileId int `json:"fileId"`
// 名称
Name string `json:"name"`
// 文件地址
Url string `json:"url"`
// 创建时间
Time string `json:"time"`
}
func (d *FileDto) Load(f *domain.File) {
d.FileId = f.FileId
d.Name = f.FileInfo.Name
d.Url = f.FileInfo.Url
d.Time = xtime.New(f.CreatedAt).Local().Format("2006-01-02 15:04:05")
}
... ...
... ... @@ -17,7 +17,7 @@ type SearchFileQuery struct {
// 页码
// PageNumber int `cname:"页码" json:"pageNumber,omitempty"`
// 页数
FileName int `cname:"文件名称" json:"fileName,omitempty"`
FileName string `cname:"文件名称" json:"fileName,omitempty"`
PageSize int `cname:"页数" json:"pageSize,omitempty"`
LastId int `cname:"最后一条记录ID" json:"lastId"`
FileType domain.FileType `cname:"文件类型" json:"fileType" valid:"Required"`
... ...
package service
import (
"github.com/linmadan/egglib-go/core/application"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/factory"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/file/command"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/file/dto"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
)
// 加载表格数据
func (fileService *FileService) LoadDataTable(loadDataTableCommand *command.LoadDataTableCommand) (interface{}, error) {
if err := loadDataTableCommand.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
if err := transactionContext.StartTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
loadDataTableService, _ := factory.CreateLoadDataTableService(transactionContext)
if _, err := loadDataTableService.Load(loadDataTableCommand.FileId); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return dto.NewDataTableDtoDemo(loadDataTableService.GetFileId()), nil
}
// 编辑表格数据
func (fileService *FileService) EditDataTable(editDataTableCommand *command.EditDataTableCommand) (interface{}, error) {
if err := editDataTableCommand.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
if err := transactionContext.StartTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return struct{}{}, nil
}
// 持久化表格数据
func (fileService *FileService) FlushDataTable(flushDataTableCommand *command.FlushDataTableCommand) (interface{}, error) {
if err := flushDataTableCommand.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
if err := transactionContext.StartTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
flushDataTableService, _ := factory.CreateFlushDataTableService(transactionContext)
fields := make([]*domain.Field, 0)
for _, f := range flushDataTableCommand.DataFields {
fields = append(fields, &domain.Field{
Name: f.Name,
SQLType: f.Type,
})
}
if _, err := flushDataTableService.Flush(flushDataTableCommand.FileId, &domain.Table{
DataFields: fields,
RowCount: flushDataTableCommand.RowCount,
}); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return struct{}{}, nil
}
// 生成主表
func (fileService *FileService) GenerateMainTable(generateMainTableCommand *command.GenerateMainTableCommand) (interface{}, error) {
if err := generateMainTableCommand.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
if err := transactionContext.StartTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
generateMainTableService, _ := factory.CreateGenerateMainTableService(transactionContext)
_, err = generateMainTableService.GenerateTable(generateMainTableCommand.FileId, generateMainTableCommand.TableName)
if err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return struct{}{}, nil
}
... ...
... ... @@ -9,6 +9,10 @@ import (
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/file/dto"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/file/query"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/domainService"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/utils"
"path/filepath"
"time"
)
// 文件服务
... ... @@ -30,92 +34,35 @@ func (fileService *FileService) CreateFile(createFileCommand *command.CreateFile
defer func() {
transactionContext.RollbackTransaction()
}()
//newFile := &domain.File{
//Name: createFileCommand.Name,
//Url: createFileCommand.Url,
//FileSize: createFileCommand.FileSize,
//}
//var fileRepository domain.FileRepository
//if value, err := factory.CreateFileRepository(map[string]interface{}{
// "transactionContext": transactionContext,
//}); err != nil {
// return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
//} else {
// fileRepository = value
//}
//file, err := fileRepository.Save(newFile)
//if err != nil {
// return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
//}
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return struct{}{}, nil
}
// 编辑表格数据
func (fileService *FileService) EditDataTable(editDataTableCommand *command.EditDataTableCommand) (interface{}, error) {
if err := editDataTableCommand.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
transactionContext, err := factory.CreateTransactionContext(nil)
newFile := &domain.File{
FileType: domain.SourceFile.ToString(),
FileInfo: &domain.FileInfo{
Name: domain.FileName(createFileCommand.Name),
Url: createFileCommand.Url,
FileSize: createFileCommand.FileSize,
Ext: filepath.Ext(createFileCommand.Name),
},
SourceFileId: 0,
Operator: "",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
fileRepository, _, _ := factory.FastPgFile(transactionContext, 0)
file, err := fileRepository.Save(newFile)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
if err := transactionContext.StartTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
if err = factory.FastLog(transactionContext, domain.CommonLog, file.FileId, &domainService.FileUploadSuccessLog{
LogEntry: domain.NewLogEntry(file.FileInfo.Name, domain.SourceFile.ToString(), domain.FileUpload, ""),
}); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return struct{}{}, nil
}
// 持久化表格数据
func (fileService *FileService) FlushDataTable(flushDataTableCommand *command.FlushDataTableCommand) (interface{}, error) {
if err := flushDataTableCommand.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
if err := transactionContext.StartTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return nil, nil
}
// 生成主表
func (fileService *FileService) GenerateMainTable(generateMainTableCommand *command.GenerateMainTableCommand) (interface{}, error) {
if err := generateMainTableCommand.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
if err := transactionContext.StartTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return nil, nil
}
// 返回文件服务
func (fileService *FileService) GetFile(getFileQuery *query.GetFileQuery) (interface{}, error) {
if err := getFileQuery.ValidateQuery(); err != nil {
... ... @@ -212,41 +159,25 @@ func (fileService *FileService) SearchFile(listFileQuery *query.SearchFileQuery)
} else {
fileRepository = value
}
count, files, err := fileRepository.Find(tool_funs.SimpleStructToMap(listFileQuery))
count, files, err := fileRepository.Find(utils.ObjectToMap(listFileQuery))
if err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
var fileDtos = make([]*dto.FileDto, 0)
for _, file := range files {
var item = &dto.FileDto{}
item.Load(file)
fileDtos = append(fileDtos, item)
}
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return map[string]interface{}{
"count": count,
"files": files,
"files": fileDtos,
}, nil
}
// 加载表格数据
func (fileService *FileService) LoadDataTable(loadDataTableCommand *command.LoadDataTableCommand) (interface{}, error) {
if err := loadDataTableCommand.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
if err := transactionContext.StartTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return dto.NewDataTableDtoDemo(), nil
}
// 移除文件服务
func (fileService *FileService) RemoveFile(removeFileCommand *command.RemoveFileCommand) (interface{}, error) {
if err := removeFileCommand.ValidateCommand(); err != nil {
... ... @@ -277,14 +208,15 @@ func (fileService *FileService) RemoveFile(removeFileCommand *command.RemoveFile
if file == nil {
return nil, application.ThrowError(application.RES_NO_FIND_ERROR, fmt.Sprintf("%s", string(removeFileCommand.FileId)))
}
if file, err := fileRepository.Remove(file); err != nil {
deleteFileService, _ := factory.CreateDeleteFileService(transactionContext)
err = deleteFileService.Delete(file)
if err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return file, nil
}
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return struct{}{}, nil
}
// 更新文件服务
... ...
package command
import (
"fmt"
"reflect"
"strings"
"github.com/beego/beego/v2/core/validation"
)
type CreateLogCommand struct {
// 对象名称 数据表名 / 文件名
ObjectName string `cname:"对象名称 数据表名 / 文件名" json:"objectName" valid:"Required"`
// 对象类型 1.主表 2.分表 3.副表 4.源文件 5.校验文件
ObjectType string `cname:"对象类型 1.主表 2.分表 3.副表 4.源文件 5.校验文件" json:"objectType" valid:"Required"`
// 操作类型 1.主表生成 2.主表拆分 3.数据导入 4.分表生成 5.表复制 6.编辑记录 7.文件上传 8.文件校验
OperationType string `cname:"操作类型 1.主表生成 2.主表拆分 3.数据导入 4.分表生成 5.表复制 6.编辑记录 7.文件上传 8.文件校验" json:"operationType" valid:"Required"`
// 日志内容
Content string `cname:"日志内容" json:"content" valid:"Required"`
// 操作人名称
OperatorName string `cname:"操作人名称" json:"operatorName" valid:"Required"`
}
func (createLogCommand *CreateLogCommand) Valid(validation *validation.Validation) {
validation.SetError("CustomValid", "未实现的自定义认证")
}
func (createLogCommand *CreateLogCommand) ValidateCommand() error {
valid := validation.Validation{}
b, err := valid.Valid(createLogCommand)
if err != nil {
return err
}
if !b {
elem := reflect.TypeOf(createLogCommand).Elem()
for _, validErr := range valid.Errors {
field, isExist := elem.FieldByName(validErr.Field)
if isExist {
return fmt.Errorf(strings.Replace(validErr.Message, validErr.Field, field.Tag.Get("cname"), -1))
} else {
return fmt.Errorf(validErr.Message)
}
}
}
return nil
}
... ...
package command
import (
"fmt"
"reflect"
"strings"
"github.com/beego/beego/v2/core/validation"
)
type RemoveLogCommand struct {
// 日志ID
LogId int `cname:"日志ID" json:"logId" valid:"Required"`
}
func (removeLogCommand *RemoveLogCommand) Valid(validation *validation.Validation) {
validation.SetError("CustomValid", "未实现的自定义认证")
}
func (removeLogCommand *RemoveLogCommand) ValidateCommand() error {
valid := validation.Validation{}
b, err := valid.Valid(removeLogCommand)
if err != nil {
return err
}
if !b {
elem := reflect.TypeOf(removeLogCommand).Elem()
for _, validErr := range valid.Errors {
field, isExist := elem.FieldByName(validErr.Field)
if isExist {
return fmt.Errorf(strings.Replace(validErr.Message, validErr.Field, field.Tag.Get("cname"), -1))
} else {
return fmt.Errorf(validErr.Message)
}
}
}
return nil
}
... ...
package command
import (
"fmt"
"reflect"
"strings"
"github.com/beego/beego/v2/core/validation"
)
type SearchLogCommand struct {
// 日志内容
Content string `cname:"日志内容" json:"content,omitempty"`
}
func (searchLogCommand *SearchLogCommand) Valid(validation *validation.Validation) {
validation.SetError("CustomValid", "未实现的自定义认证")
}
func (searchLogCommand *SearchLogCommand) ValidateCommand() error {
valid := validation.Validation{}
b, err := valid.Valid(searchLogCommand)
if err != nil {
return err
}
if !b {
elem := reflect.TypeOf(searchLogCommand).Elem()
for _, validErr := range valid.Errors {
field, isExist := elem.FieldByName(validErr.Field)
if isExist {
return fmt.Errorf(strings.Replace(validErr.Message, validErr.Field, field.Tag.Get("cname"), -1))
} else {
return fmt.Errorf(validErr.Message)
}
}
}
return nil
}
... ...
package command
import (
"fmt"
"reflect"
"strings"
"github.com/beego/beego/v2/core/validation"
)
type UpdateLogCommand struct {
// 日志ID
LogId int `cname:"日志ID" json:"logId" valid:"Required"`
}
func (updateLogCommand *UpdateLogCommand) Valid(validation *validation.Validation) {
validation.SetError("CustomValid", "未实现的自定义认证")
}
func (updateLogCommand *UpdateLogCommand) ValidateCommand() error {
valid := validation.Validation{}
b, err := valid.Valid(updateLogCommand)
if err != nil {
return err
}
if !b {
elem := reflect.TypeOf(updateLogCommand).Elem()
for _, validErr := range valid.Errors {
field, isExist := elem.FieldByName(validErr.Field)
if isExist {
return fmt.Errorf(strings.Replace(validErr.Message, validErr.Field, field.Tag.Get("cname"), -1))
} else {
return fmt.Errorf(validErr.Message)
}
}
}
return nil
}
... ...
package query
import (
"fmt"
"reflect"
"strings"
"github.com/beego/beego/v2/core/validation"
)
type GetLogQuery struct {
// 日志ID
LogId int `cname:"日志ID" json:"logId" valid:"Required"`
}
func (getLogQuery *GetLogQuery) Valid(validation *validation.Validation) {
validation.SetError("CustomValid", "未实现的自定义认证")
}
func (getLogQuery *GetLogQuery) ValidateQuery() error {
valid := validation.Validation{}
b, err := valid.Valid(getLogQuery)
if err != nil {
return err
}
if !b {
elem := reflect.TypeOf(getLogQuery).Elem()
for _, validErr := range valid.Errors {
field, isExist := elem.FieldByName(validErr.Field)
if isExist {
return fmt.Errorf(strings.Replace(validErr.Message, validErr.Field, field.Tag.Get("cname"), -1))
} else {
return fmt.Errorf(validErr.Message)
}
}
}
return nil
}
... ...
package query
import (
"fmt"
"reflect"
"strings"
"github.com/beego/beego/v2/core/validation"
)
type ListLogQuery struct {
// 查询偏离量
Offset int `cname:"查询偏离量" json:"offset" valid:"Required"`
// 查询限制
Limit int `cname:"查询限制" json:"limit" valid:"Required"`
}
func (listLogQuery *ListLogQuery) Valid(validation *validation.Validation) {
validation.SetError("CustomValid", "未实现的自定义认证")
}
func (listLogQuery *ListLogQuery) ValidateQuery() error {
valid := validation.Validation{}
b, err := valid.Valid(listLogQuery)
if err != nil {
return err
}
if !b {
elem := reflect.TypeOf(listLogQuery).Elem()
for _, validErr := range valid.Errors {
field, isExist := elem.FieldByName(validErr.Field)
if isExist {
return fmt.Errorf(strings.Replace(validErr.Message, validErr.Field, field.Tag.Get("cname"), -1))
} else {
return fmt.Errorf(validErr.Message)
}
}
}
return nil
}
... ...
package service
import (
"fmt"
"github.com/linmadan/egglib-go/core/application"
"github.com/linmadan/egglib-go/utils/tool_funs"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/factory"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/log/command"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/log/query"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
)
// 日志服务
type LogService struct {
}
// 创建日志服务
func (logService *LogService) CreateLog(createLogCommand *command.CreateLogCommand) (interface{}, error) {
if err := createLogCommand.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
if err := transactionContext.StartTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
newLog := &domain.Log{
ObjectName: createLogCommand.ObjectName,
ObjectType: createLogCommand.ObjectType,
OperationType: createLogCommand.OperationType,
Content: createLogCommand.Content,
OperatorName: createLogCommand.OperatorName,
}
var logRepository domain.LogRepository
if value, err := factory.CreateLogRepository(map[string]interface{}{
"transactionContext": transactionContext,
}); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
logRepository = value
}
if log, err := logRepository.Save(newLog); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return log, nil
}
}
// 返回日志服务
func (logService *LogService) GetLog(getLogQuery *query.GetLogQuery) (interface{}, error) {
if err := getLogQuery.ValidateQuery(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
if err := transactionContext.StartTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
var logRepository domain.LogRepository
if value, err := factory.CreateLogRepository(map[string]interface{}{
"transactionContext": transactionContext,
}); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
logRepository = value
}
log, err := logRepository.FindOne(map[string]interface{}{"logId": getLogQuery.LogId})
if err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
if log == nil {
return nil, application.ThrowError(application.RES_NO_FIND_ERROR, fmt.Sprintf("%s", string(getLogQuery.LogId)))
} else {
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return log, nil
}
}
// 返回日志服务列表
func (logService *LogService) ListLog(listLogQuery *query.ListLogQuery) (interface{}, error) {
if err := listLogQuery.ValidateQuery(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
if err := transactionContext.StartTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
var logRepository domain.LogRepository
if value, err := factory.CreateLogRepository(map[string]interface{}{
"transactionContext": transactionContext,
}); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
logRepository = value
}
if count, logs, err := logRepository.Find(tool_funs.SimpleStructToMap(listLogQuery)); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return map[string]interface{}{
"count": count,
"logs": logs,
}, nil
}
}
// 移除日志服务
func (logService *LogService) RemoveLog(removeLogCommand *command.RemoveLogCommand) (interface{}, error) {
if err := removeLogCommand.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
if err := transactionContext.StartTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
var logRepository domain.LogRepository
if value, err := factory.CreateLogRepository(map[string]interface{}{
"transactionContext": transactionContext,
}); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
logRepository = value
}
log, err := logRepository.FindOne(map[string]interface{}{"logId": removeLogCommand.LogId})
if err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
if log == nil {
return nil, application.ThrowError(application.RES_NO_FIND_ERROR, fmt.Sprintf("%s", string(removeLogCommand.LogId)))
}
if log, err := logRepository.Remove(log); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return log, nil
}
}
// 搜索日志
func (logService *LogService) SearchLog(searchLogCommand *command.SearchLogCommand) (interface{}, error) {
if err := searchLogCommand.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
if err := transactionContext.StartTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return nil, nil
}
// 更新日志服务
func (logService *LogService) UpdateLog(updateLogCommand *command.UpdateLogCommand) (interface{}, error) {
if err := updateLogCommand.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
if err := transactionContext.StartTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
var logRepository domain.LogRepository
if value, err := factory.CreateLogRepository(map[string]interface{}{
"transactionContext": transactionContext,
}); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
logRepository = value
}
log, err := logRepository.FindOne(map[string]interface{}{"logId": updateLogCommand.LogId})
if err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
if log == nil {
return nil, application.ThrowError(application.RES_NO_FIND_ERROR, fmt.Sprintf("%s", string(updateLogCommand.LogId)))
}
if err := log.Update(tool_funs.SimpleStructToMap(updateLogCommand)); err != nil {
return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error())
}
if log, err := logRepository.Save(log); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return log, nil
}
}
func NewLogService(options map[string]interface{}) *LogService {
newLogService := &LogService{}
return newLogService
}
... ...
... ... @@ -8,12 +8,6 @@ var (
// 是否关闭仓储层缓存
ENABLE_REPOSITORY_CACHE = true
// 缓存过期时间 单位秒
REPOSITORY_CACHE_EXPIRE = 30 * 60
// redis 考勤机打卡消息队列
REDIS_ZKTECO_KEY = "allied-creation-zkteco"
// redis 车间数据消息队列
REDIS_WORKSHOP_KEY = "allied-creation-workshop"
)
func init() {
... ...
package domain
type LoadDataTableService interface {
Load(fileId int) (interface{}, error)
GetFileId() int
}
type FlushDataTableService interface {
Flush(fileId int, table *Table) (interface{}, error)
}
type DeleteFileService interface {
Delete(files ...*File) error
}
type GenerateMainTableService interface {
GenerateTable(fileId int, tableName string) (interface{}, error)
}
... ...
package domain
type FileType string
import "fmt"
var (
SourceFile FileType = "SourceFile"
VerifiedFile FileType = "VerifiedFile"
TemporaryFile FileType = "TemporaryFile"
ErrorNotFound = fmt.Errorf("没有此资源")
)
var (
GenerateMainTable OperationType = "GenerateMainTable" // 主表生成
SpiltMainTable OperationType = "SpiltMainTable" //主表拆分
ImportData OperationType = "ImportData" //数据导入
GenerateSubTable OperationType = "GenerateSubTable" //分表生成
AppendData OperationType = "AppendData" //数据追加
EditSubTable OperationType = "EditSubTable" //分表编辑
CopyTable OperationType = "CopyTable" //表复制
RowEdit OperationType = "RowEdit" // 编辑记录
DeleteTable OperationType = "DeleteTable" // 表删除
FileUpload OperationType = "FileUpload" // 文件上传
FileVerify OperationType = "FileVerify" // 文件校验
)
var OperationTypeMap = map[string]string{
GenerateMainTable.ToString(): "主表生成",
SpiltMainTable.ToString(): "主表拆分",
AppendData.ToString(): "数据追加",
EditSubTable.ToString(): "分表编辑",
CopyTable.ToString(): "表复制",
RowEdit.ToString(): "编辑记录",
DeleteTable.ToString(): "表删除",
FileUpload.ToString(): "文件上传",
FileVerify.ToString(): "文件校验",
}
var (
VerifiedStepLog LogType = "VerifiedStepLog"
CommonLog LogType = "CommonLog"
)
var (
PKField int = 0 // 主键字段
MainTableField int = 1 // 主表字段
ManualField int = 2 // 手动添加
)
var (
MainTable TableType = "MainTable"
SideTable TableType = "SideTable"
SubTable TableType = "SubTable"
ExcelTable TableType = "ExcelTable"
)
var (
SourceFile FileType = "SourceFile"
VerifiedFile FileType = "VerifiedFile"
TemporaryFile FileType = "TemporaryFile"
)
var ObjectTypeMap = map[string]string{
MainTable.ToString(): "主表",
SideTable.ToString(): "副表",
SubTable.ToString(): "分表",
SourceFile.ToString(): "源文件",
VerifiedFile.ToString(): "校验文件",
}
var (
VerifiedStepLog LogType = 1
CommonLog LogType = 2
XLS = ".xls"
XLSX = ".xlsx"
)
var (
MainTable TableType = "MainTable"
SideTable TableType = "SideTable"
SubTable TableType = "SubTable"
ExcelTable TableType = "ExcelTable"
VerifiedExcelTable TableType = "VerifiedExcelTable"
String SQLType = "string"
Int SQLType = "int"
Float SQLType = "float"
Date SQLType = "date"
Datetime SQLType = "datetime"
)
type FileType string
func (t FileType) ToString() string {
return string(t)
}
type LogType int
type LogType string
func (t LogType) ToString() string {
return string(t)
}
type TableType string
... ... @@ -51,3 +100,16 @@ type OperationType string
func (t OperationType) ToString() string {
return string(t)
}
type SQLType string
func (t SQLType) ToString() string {
return string(t)
}
func EnumsDescription(m map[string]string, key string) string {
if v, ok := m[key]; ok {
return v
}
return ""
}
... ...
... ... @@ -3,7 +3,7 @@ package domain
// Field 字段
type Field struct {
// 字段Id
FieldId int `json:"fieldId"`
// FieldId int `json:"fieldId"`
// 索引序号
Index int `json:"index"`
// 名称
... ...
package domain
import "time"
import (
"path/filepath"
"strings"
"time"
)
// File 文件
type File struct {
... ... @@ -11,7 +15,7 @@ type File struct {
// 文件信息
FileInfo *FileInfo `json:"fileInfo"`
// 源文件Id(FileType为TemporaryFile或VerifiedFile时有值)
SourceFileId string `json:"sourceFileId"`
SourceFileId int `json:"sourceFileId"`
// 操作人
Operator string `json:"operator"`
// 创建时间
... ... @@ -41,3 +45,26 @@ func (file *File) Identify() interface{} {
func (file *File) Update(data map[string]interface{}) error {
return nil
}
func FileName(fileName string) string {
base := filepath.Base(fileName)
return strings.Split(base, ".")[0]
}
func (file *File) CopyTo(fileType FileType) *File {
t := &File{
FileType: fileType.ToString(),
FileInfo: &FileInfo{
Name: file.FileInfo.Name,
FileSize: file.FileInfo.FileSize,
Url: file.FileInfo.Url,
Ext: file.FileInfo.Ext,
RowCount: file.FileInfo.RowCount,
},
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
SourceFileId: file.FileId,
Operator: file.Operator,
}
return t
}
... ...
... ... @@ -8,4 +8,12 @@ type FileInfo struct {
Url string `json:"url"`
// 文件大小
FileSize int `json:"fileSize"`
// 文件编号,以固定字符“F”+4位年+2位月+2位日+三位流水,每天编号从001开始
// FileCode string `json:"fileCode"`
//
Ext string `json:"ext"`
// 记录数
RowCount int `json:"rowCount"`
// 表结构ID
TableId int `json:"tableId"`
}
... ...
... ... @@ -7,11 +7,21 @@ type Log struct {
// 日志ID
LogId int `json:"logId"`
// 日志类型 1.校验步骤 2.常规日志
LogType int `json:"logType"`
LogType string `json:"logType"`
// 源数据ID
SourceId int `json:"sourceId"`
// 日志内容
Entry *LogEntry `json:"entry"`
// 对象名称 数据表名 / 文件名
ObjectName string `json:"objectName"`
// 对象类型 1.主表 2.分表 3.副表 4.源文件 5.校验文件
ObjectType string `json:"objectType"`
// 操作类型 1.主表生成 2.主表拆分 3.数据导入 4.分表生成 5.表复制 6.编辑记录 7.文件上传 8.文件校验
OperationType string `json:"operationType"`
// 日志内容
Content string `json:"content"`
// 操作人名称
OperatorName string `json:"operatorName"`
// 创建时间
CreatedAt time.Time `json:"createdAt"`
}
... ...
... ... @@ -13,3 +13,16 @@ type LogEntry struct {
// 操作人名称
OperatorName string `json:"operatorName"`
}
func (l LogEntry) Entry() LogEntry {
return l
}
func NewLogEntry(fileOrTableName string, objectType string, operationType OperationType, operatorName string) LogEntry {
return LogEntry{
ObjectName: fileOrTableName,
ObjectType: objectType,
OperationType: operationType.ToString(),
OperatorName: operatorName,
}
}
... ...
... ... @@ -11,9 +11,9 @@ type Table struct {
// 名称
Name string `json:"name"`
// 对应数据库名称
SQLName string `json:"sQLName"`
SQLName string `json:"sqlName"`
// 父级ID
ParentId int64 `json:"parentId,string"`
ParentId int `json:"parentId"`
// 数据字段序号
DataFieldIndex int `json:"dataFieldIndex"`
// 主键字段
... ... @@ -30,6 +30,9 @@ type Table struct {
DeletedAt time.Time `json:"deletedAt"`
// 版本
Version int `json:"version"`
// 业务字段
RowCount int `json:"rowCount,omitempty"`
}
type TableRepository interface {
... ...
package dao
import (
"github.com/go-pg/pg/v10"
pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
)
func FileDelete(ptr *pgTransaction.TransactionContext, fileId int, fileType domain.FileType) error {
sql := "delete from metadata.files where file_id = ? and file_type = ?"
_, err := ptr.PgTx.Exec(sql, fileId, fileType.ToString())
return err
}
func FileDeleteBySourceFileId(ptr *pgTransaction.TransactionContext, fileId int, fileType domain.FileType, excludeFileIs ...int) error {
sql := "delete from metadata.files where source_file_id = ? and file_type =? and file_id not in (?)"
_, err := ptr.PgTx.Exec(sql, fileId, fileType.ToString(), pg.In(excludeFileIs))
return err
}
... ...
package dao
import (
pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
)
func ChangeStepLogOwner(ptr *pgTransaction.TransactionContext, from int, to int) error {
sql := "update metadata.logs set source_id = ? where source_id=? and log_type=?"
_, err := ptr.PgTx.Exec(sql, to, from, domain.VerifiedStepLog)
return err
}
func LogDelete(ptr *pgTransaction.TransactionContext, sourceId int, logType domain.LogType) error {
sql := "delete from metadata.logs where source_id = ? and log_type = ?"
_, err := ptr.PgTx.Exec(sql, sourceId, logType)
return err
}
... ...
package dao
import (
pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
)
func TableDelete(ptr *pgTransaction.TransactionContext, tableId int, tableType domain.TableType) error {
sql := "delete from metadata.tables where table_id = ? and table_type = ?"
_, err := ptr.PgTx.Exec(sql, tableId, tableType.ToString())
return err
}
... ...
package domainService
import (
"fmt"
pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/dao"
)
type DeleteFileService struct {
transactionContext *pgTransaction.TransactionContext
}
func NewDeleteFileService(transactionContext *pgTransaction.TransactionContext) (*DeleteFileService, error) {
if transactionContext == nil {
return nil, fmt.Errorf("transactionContext参数不能为nil")
} else {
return &DeleteFileService{
transactionContext: transactionContext,
}, nil
}
}
func (ptr *DeleteFileService) Delete(files ...*domain.File) error {
for _, file := range files {
if err := ptr.delete(file); err != nil {
return err
}
}
return nil
}
func (ptr *DeleteFileService) delete(file *domain.File) error {
// delete file
if err := dao.FileDelete(ptr.transactionContext, file.FileId, domain.FileType(file.FileType)); err != nil {
return err
}
// delete table
if file.FileInfo.TableId > 0 {
if err := dao.TableDelete(ptr.transactionContext, file.FileInfo.TableId, domain.ExcelTable); err != nil {
return err
}
}
// delete log
if err := dao.LogDelete(ptr.transactionContext, file.FileId, domain.VerifiedStepLog); err != nil {
return err
}
return nil
}
... ...
package domainService
import pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
type DeleteTableService struct {
transactionContext *pgTransaction.TransactionContext
}
func (ptr *DeleteTableService) Delete(tableIds ...int) error {
// delete table
// delete log
return nil
}
... ...
package domainService
import (
"fmt"
"github.com/google/uuid"
pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/dao"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/repository"
"time"
)
type FlushDataTableService struct {
FileId int
transactionContext *pgTransaction.TransactionContext
}
func (ptr *FlushDataTableService) Flush(fileId int, table *domain.Table) (interface{}, error) {
fileRepository, _ := repository.NewFileRepository(ptr.transactionContext)
file, err := fileRepository.FindOne(map[string]interface{}{"fileId": fileId})
if err != nil {
return nil, fmt.Errorf("临时文件不存在")
}
sourceFile, err := fileRepository.FindOne(map[string]interface{}{"fileId": file.SourceFileId})
if err != nil {
return nil, fmt.Errorf("源文件不存在")
}
// New Table
table = NewTable(domain.ExcelTable, file.FileInfo.Name, table.DataFields, table.RowCount)
// 来自源文件的
// 临时文件 -》校验文件
switch sourceFile.FileType {
case domain.SourceFile.ToString():
if err = ptr.flushSourceFile(table, file, sourceFile, fileRepository); err != nil {
return nil, err
}
case domain.VerifiedFile.ToString():
if err = ptr.flushVerifiedFile(table, file, sourceFile, fileRepository); err != nil {
return nil, err
}
}
// 日志
if err = FastLog(ptr.transactionContext, domain.CommonLog, file.FileId, &FileVerifyLog{
LogEntry: domain.NewLogEntry(file.FileInfo.Name, domain.VerifiedFile.ToString(), domain.FileVerify, ""),
Total: table.RowCount,
}); err != nil {
return nil, err
}
// 通知底层保存、进行回调
return struct{}{}, nil
}
func (ptr *FlushDataTableService) flushSourceFile(table *domain.Table, file *domain.File, sourceFile *domain.File, fileRepository domain.FileRepository) error {
var err error
// 新增
tableRepository, _ := repository.NewTableRepository(ptr.transactionContext)
table, err = tableRepository.Save(table)
if err != nil {
return err
}
file.FileInfo.TableId = table.TableId
file.FileType = domain.VerifiedFile.ToString()
if file, err = fileRepository.Save(file); err != nil {
return err
}
// 删除跟源文件有关系的校验文件
//if err = dao.FileDeleteBySourceFileId(ptr.transactionContext, sourceFile.FileId, domain.VerifiedFile, file.FileId); err != nil {
// return err
//}
_, files, err := fileRepository.Find(map[string]interface{}{"sourceFileId": sourceFile.FileId, "fileType": domain.VerifiedFile.ToString(), "notInFileIds": []int{file.FileId}})
if err != nil {
return err
}
deleteFileService, _ := NewDeleteFileService(ptr.transactionContext)
if err = deleteFileService.Delete(files...); err != nil {
return err
}
return nil
}
func (ptr *FlushDataTableService) flushVerifiedFile(table *domain.Table, file *domain.File, sourceFile *domain.File, fileRepository domain.FileRepository) error {
var err error
temporaryFileTableId := table.TableId
// 校验文件对应的表更新
table.TableId = file.FileInfo.TableId
// 追加日志到校验文件
if err = dao.ChangeStepLogOwner(ptr.transactionContext, file.FileId, sourceFile.FileId); err != nil {
return err
}
// 删除中间文件
if err = dao.FileDelete(ptr.transactionContext, file.FileId, domain.TemporaryFile); err != nil {
return err
}
// 删除中间表
if err = dao.TableDelete(ptr.transactionContext, temporaryFileTableId, domain.ExcelTable); err != nil {
return err
}
if _, err = fileRepository.Save(sourceFile); err != nil {
return err
}
// 更新
tableRepository, _ := repository.NewTableRepository(ptr.transactionContext)
table, err = tableRepository.Save(table)
if err != nil {
return err
}
return nil
}
func NewFlushDataTableService(transactionContext *pgTransaction.TransactionContext) (*FlushDataTableService, error) {
if transactionContext == nil {
return nil, fmt.Errorf("transactionContext参数不能为nil")
} else {
return &FlushDataTableService{
transactionContext: transactionContext,
}, nil
}
}
func NewTable(tableType domain.TableType, fileName string, dataFields []*domain.Field, rowCount int) *domain.Table {
var table = &domain.Table{}
// New Table
table.TableType = tableType.ToString()
table.Name = fileName
table.SQLName = SQLTableName()
table.PK = PK()
table.DataFieldIndex = len(dataFields)
for i, field := range dataFields {
table.DataFields = append(table.DataFields, DataField(field.Name, field.SQLType, domain.MainTableField, i))
}
table.ManualFields = make([]*domain.Field, 0)
table.CreatedAt = time.Now()
table.UpdatedAt = time.Now()
table.RowCount = rowCount
return table
}
func SQLTableName() string {
id, _ := uuid.NewUUID()
return id.String()
}
func PK() *domain.Field {
return &domain.Field{
Index: 0,
Name: "序号",
SQLName: "id",
SQLType: domain.Int.ToString(),
Description: "主键",
Flag: 0,
}
}
func DataField(name string, sqlType string, flag int, index int) *domain.Field {
return &domain.Field{
Index: index,
Name: name,
SQLName: fieldName(index + 1),
SQLType: sqlType,
Description: "",
Flag: flag,
}
}
func fieldName(index int) string {
return fmt.Sprintf("col%02d", index)
}
... ...
package domainService
import (
"fmt"
pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/repository"
)
type GenerateMainTableService struct {
transactionContext *pgTransaction.TransactionContext
}
func (ptr *GenerateMainTableService) GenerateTable(fileId int, tableName string) (interface{}, error) {
fileRepository, _ := repository.NewFileRepository(ptr.transactionContext)
file, err := fileRepository.FindOne(map[string]interface{}{"fileId": fileId})
if err != nil {
return nil, fmt.Errorf("文件不存在")
}
tableRepository, _ := repository.NewTableRepository(ptr.transactionContext)
table, err := tableRepository.FindOne(map[string]interface{}{"tableId": file.FileInfo.TableId})
if err != nil {
return nil, fmt.Errorf("文件未校验")
}
mainTable := NewTable(domain.MainTable, tableName, table.DataFields, table.RowCount)
_, err = tableRepository.Save(mainTable)
if err != nil {
return nil, err
}
return struct{}{}, nil
}
func NewGenerateMainTableService(transactionContext *pgTransaction.TransactionContext) (*GenerateMainTableService, error) {
if transactionContext == nil {
return nil, fmt.Errorf("transactionContext参数不能为nil")
} else {
return &GenerateMainTableService{
transactionContext: transactionContext,
}, nil
}
}
... ...
package domainService
import (
"fmt"
pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/repository"
)
type LoadDataTableService struct {
FileId int
transactionContext *pgTransaction.TransactionContext
}
func (ptr *LoadDataTableService) Load(fileId int) (interface{}, error) {
fileRepository, _ := repository.NewFileRepository(ptr.transactionContext)
file, err := fileRepository.FindOne(map[string]interface{}{"fileId": fileId})
if err != nil {
return nil, fmt.Errorf("文件不存在")
}
// Copy to TemporaryFile
if file.FileType != domain.TemporaryFile.ToString() {
file = file.CopyTo(domain.TemporaryFile)
if file, err = fileRepository.Save(file); err != nil {
return nil, err
}
}
//TEST
ptr.FileId = file.FileId
// Load Data From Excel(python api)
return map[string]interface{}{
"fileId": file.FileId,
}, nil
}
func (ptr *LoadDataTableService) GetFileId() int {
return ptr.FileId
}
func NewLoadDataTableService(transactionContext *pgTransaction.TransactionContext) (*LoadDataTableService, error) {
if transactionContext == nil {
return nil, fmt.Errorf("transactionContext参数不能为nil")
} else {
return &LoadDataTableService{
transactionContext: transactionContext,
}, nil
}
}
... ...
package domainService
import (
"fmt"
pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/repository"
"time"
)
type PGLogService struct {
transactionContext *pgTransaction.TransactionContext
}
func NewPGLogService(transactionContext *pgTransaction.TransactionContext) (*PGLogService, error) {
if transactionContext == nil {
return nil, fmt.Errorf("transactionContext参数不能为nil")
} else {
return &PGLogService{
transactionContext: transactionContext,
}, nil
}
}
func FastLog(transactionContext *pgTransaction.TransactionContext, logType domain.LogType, sourceId int, logEntry Log) error {
logService, _ := NewPGLogService(transactionContext)
return logService.Log(logType, sourceId, logEntry)
}
func (ptr *PGLogService) Log(logType domain.LogType, sourceId int, logEntry Log) error {
logRepository, _ := repository.NewLogRepository(ptr.transactionContext)
entry := logEntry.Entry()
log := &domain.Log{
LogType: logType.ToString(),
SourceId: sourceId,
Entry: &entry,
ObjectName: entry.ObjectName,
ObjectType: domain.EnumsDescription(domain.ObjectTypeMap, entry.ObjectType),
OperationType: domain.EnumsDescription(domain.OperationTypeMap, entry.OperationType),
Content: logEntry.Content(),
OperatorName: entry.OperatorName,
CreatedAt: time.Now(),
}
_, err := logRepository.Save(log)
return err
}
func (ptr *PGLogService) NewLogEntry() domain.LogEntry {
return domain.LogEntry{}
}
type Log interface {
Content() string
Entry() domain.LogEntry
}
var _ Log = (*FileUploadSuccessLog)(nil)
// 1.1文件上传成功
type FileUploadSuccessLog struct {
domain.LogEntry
}
func (l *FileUploadSuccessLog) Content() string {
return fmt.Sprintf("上传成功")
}
// 1.2文件上传失败
type FileUploadFailLog struct {
domain.LogEntry
Reason string
}
func (l *FileUploadFailLog) Content() string {
return fmt.Sprintf("上传失败,失败原因:%s", l.Reason)
}
// 2.文件校验
type FileVerifyLog struct {
domain.LogEntry
// 错误信息
Errors []string
// 记录数
Total int
}
func (l *FileVerifyLog) Content() string {
msg := fmt.Sprintf("校验完成,共计%d条记录 ", l.Total)
if len(l.Errors) > 0 {
msg += fmt.Sprintf("存在%v条报错", len(l.Errors))
}
return msg
}
... ...
package pg
import (
"context"
"fmt"
"github.com/beego/beego/v2/core/logs"
"github.com/go-pg/pg/v10"
"github.com/go-pg/pg/v10/orm"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/constant"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/pg/models"
//_ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/pg/models"
"github.com/linmadan/egglib-go/persistent/pg/comment"
"github.com/linmadan/egglib-go/persistent/pg/hooks"
"log"
)
var DB *pg.DB
func init() {
func Init() {
DB = pg.Connect(&pg.Options{
User: constant.POSTGRESQL_USER,
Password: constant.POSTGRESQL_PASSWORD,
... ... @@ -22,7 +21,7 @@ func init() {
Addr: fmt.Sprintf("%s:%s", constant.POSTGRESQL_HOST, constant.POSTGRESQL_PORT),
})
if !constant.DISABLE_SQL_GENERATE_PRINT {
DB.AddQueryHook(hooks.SqlGeneratePrintHook{})
DB.AddQueryHook(SqlGeneratePrintHook{})
}
if !constant.DISABLE_CREATE_TABLE {
for _, model := range []interface{}{
... ... @@ -38,7 +37,24 @@ func init() {
if err != nil {
panic(err)
}
comment.AddComments(DB, model)
//comment.AddComments(DB, model)
}
}
}
type SqlGeneratePrintHook struct{}
func (hook SqlGeneratePrintHook) BeforeQuery(c context.Context, q *pg.QueryEvent) (context.Context, error) {
return c, nil
}
func (hook SqlGeneratePrintHook) AfterQuery(c context.Context, q *pg.QueryEvent) error {
sqlStr, err := q.FormattedQuery()
if err != nil {
return err
}
//log.Logger.Debug(string(sqlStr))
log.Println(string(sqlStr))
logs.Debug(string(sqlStr))
return nil
}
... ...
... ... @@ -14,7 +14,7 @@ type File struct {
// 文件信息
FileInfo *domain.FileInfo `comment:"文件信息"`
// 源文件Id(FileType为TemporaryFile或VerifiedFile时有值)
SourceFileId string `comment:"源文件Id(FileType为TemporaryFile或VerifiedFile时有值)"`
SourceFileId int `comment:"源文件Id(FileType为TemporaryFile或VerifiedFile时有值)"`
// 操作人
Operator string `comment:"操作人"`
// 创建时间
... ...
... ... @@ -10,11 +10,21 @@ type Log struct {
// 日志ID
LogId int `comment:"日志ID" pg:"pk:log_id"`
// 日志类型 1.校验步骤 2.常规日志
LogType int `comment:"日志类型 1.校验步骤 2.常规日志"`
LogType string `comment:"日志类型 1.校验步骤 2.常规日志"`
// 源数据ID
SourceId int `comment:"源数据ID"`
// 日志内容
Entry *domain.LogEntry `comment:"日志内容"`
// 对象名称 数据表名 / 文件名
ObjectName string `json:"objectName"`
// 对象类型 1.主表 2.分表 3.副表 4.源文件 5.校验文件
ObjectType string `json:"objectType"`
// 操作类型 1.主表生成 2.主表拆分 3.数据导入 4.分表生成 5.表复制 6.编辑记录 7.文件上传 8.文件校验
OperationType string `json:"operationType"`
// 日志内容
Content string `json:"content"`
// 操作人名称
OperatorName string `json:"operatorName"`
// 创建时间
CreatedAt time.Time `comment:"创建时间"`
}
... ...
... ... @@ -16,7 +16,7 @@ type Table struct {
// 对应数据库名称
SQLName string `comment:"对应数据库名称"`
// 父级ID
ParentId int64 `comment:"父级ID"`
ParentId int `comment:"父级ID"`
// 数据字段序号
DataFieldIndex int `comment:"数据字段序号"`
// 主键字段
... ...
... ... @@ -7,10 +7,15 @@ import (
func TransformToLogDomainModelFromPgModels(logModel *models.Log) (*domain.Log, error) {
return &domain.Log{
LogId: logModel.LogId,
LogType: logModel.LogType,
SourceId: logModel.SourceId,
Entry: logModel.Entry,
CreatedAt: logModel.CreatedAt,
LogId: logModel.LogId,
LogType: logModel.LogType,
SourceId: logModel.SourceId,
Entry: logModel.Entry,
ObjectName: logModel.ObjectName,
ObjectType: logModel.ObjectType,
OperationType: logModel.OperationType,
Content: logModel.Content,
OperatorName: logModel.OperatorName,
CreatedAt: logModel.CreatedAt,
}, nil
}
... ...
... ... @@ -3,7 +3,6 @@ package repository
import (
"fmt"
"github.com/go-pg/pg/v10"
"github.com/linmadan/egglib-go/persistent/pg/sqlbuilder"
pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
"github.com/linmadan/egglib-go/utils/snowflake"
... ... @@ -56,7 +55,6 @@ func (repository *FileRepository) Save(file *domain.File) (*domain.File, error)
&file.Version,
),
fmt.Sprintf("INSERT INTO metadata.files (%s) VALUES (%s) RETURNING %s", insertFieldsSnippet, insertPlaceHoldersSnippet, returningFieldsSnippet),
file.FileId,
file.FileType,
file.FileInfo,
file.SourceFileId,
... ... @@ -83,14 +81,12 @@ func (repository *FileRepository) Save(file *domain.File) (*domain.File, error)
&file.Version,
),
fmt.Sprintf("UPDATE metadata.files SET %s WHERE file_id=? and version=? RETURNING %s", updateFieldsSnippet, returningFieldsSnippet),
file.FileId,
file.FileType,
file.FileInfo,
file.SourceFileId,
file.Operator,
file.CreatedAt,
file.UpdatedAt,
file.DeletedAt,
file.Version,
file.Identify(),
oldVersion,
... ... @@ -132,6 +128,15 @@ func (repository *FileRepository) Find(queryOptions map[string]interface{}) (int
var fileModels []*models.File
files := make([]*domain.File, 0)
query := sqlbuilder.BuildQuery(tx.Model(&fileModels), queryOptions)
query.SetWhereByQueryOption("file_id > ?", "lastId")
query.SetWhereByQueryOption("file_type = ?", "fileType")
query.SetWhereByQueryOption(fmt.Sprintf("file_info->>'name' like '%%%v%%'", queryOptions["fileName"]), "fileName")
query.SetWhereByQueryOption("source_file_id = ?", "sourceFileId")
if v, ok := queryOptions["notInFileIds"]; ok && len(v.([]int)) > 0 {
query.Where(`file_id not in (?)`, pg.In(v.([]int)))
}
query.SetOffsetAndLimit(20)
query.SetOrderDirect("file_id", "DESC")
if count, err := query.SelectAndCount(); err != nil {
... ...
... ... @@ -29,8 +29,13 @@ func (repository *LogRepository) Save(log *domain.Log) (*domain.Log, error) {
"log_id",
"log_type",
"source_id",
"entry",
"object_name",
"object_type",
"operation_type",
"content",
"operator_name",
"created_at",
"entry",
}
insertFieldsSnippet := sqlbuilder.SqlFieldsSnippet(sqlbuilder.RemoveSqlFields(sqlBuildFields, "log_id"))
insertPlaceHoldersSnippet := sqlbuilder.SqlPlaceHoldersSnippet(sqlbuilder.RemoveSqlFields(sqlBuildFields, "log_id"))
... ... @@ -44,15 +49,24 @@ func (repository *LogRepository) Save(log *domain.Log) (*domain.Log, error) {
&log.LogId,
&log.LogType,
&log.SourceId,
&log.Entry,
&log.ObjectName,
&log.ObjectType,
&log.OperationType,
&log.Content,
&log.OperatorName,
&log.CreatedAt,
&log.Entry,
),
fmt.Sprintf("INSERT INTO metadata.logs (%s) VALUES (%s) RETURNING %s", insertFieldsSnippet, insertPlaceHoldersSnippet, returningFieldsSnippet),
//log.LogId,
log.LogType,
log.SourceId,
log.Entry,
log.ObjectName,
log.ObjectType,
log.OperationType,
log.Content,
log.OperatorName,
log.CreatedAt,
log.Entry,
); err != nil {
return log, err
}
... ... @@ -62,15 +76,24 @@ func (repository *LogRepository) Save(log *domain.Log) (*domain.Log, error) {
&log.LogId,
&log.LogType,
&log.SourceId,
&log.Entry,
&log.ObjectName,
&log.ObjectType,
&log.OperationType,
&log.Content,
&log.OperatorName,
&log.CreatedAt,
&log.Entry,
),
fmt.Sprintf("UPDATE metadata.logs SET %s WHERE log_id=? RETURNING %s", updateFieldsSnippet, returningFieldsSnippet),
//log.LogId,
log.LogType,
log.SourceId,
log.Entry,
log.ObjectName,
log.ObjectType,
log.OperationType,
log.Content,
log.OperatorName,
log.CreatedAt,
&log.Entry,
log.Identify(),
); err != nil {
return log, err
... ...
... ... @@ -40,10 +40,10 @@ func (repository *TableRepository) Save(table *domain.Table) (*domain.Table, err
"deleted_at",
"version",
}
insertFieldsSnippet := sqlbuilder.SqlFieldsSnippet(sqlBuildFields)
insertPlaceHoldersSnippet := sqlbuilder.SqlPlaceHoldersSnippet(sqlBuildFields)
insertFieldsSnippet := sqlbuilder.SqlFieldsSnippet(sqlbuilder.RemoveSqlFields(sqlBuildFields, "table_id", "deleted_at"))
insertPlaceHoldersSnippet := sqlbuilder.SqlPlaceHoldersSnippet(sqlbuilder.RemoveSqlFields(sqlBuildFields, "table_id", "deleted_at"))
returningFieldsSnippet := sqlbuilder.SqlFieldsSnippet(sqlBuildFields)
updateFields := sqlbuilder.RemoveSqlFields(sqlBuildFields, "table_id")
updateFields := sqlbuilder.RemoveSqlFields(sqlBuildFields, "table_id", "deleted_at")
updateFieldsSnippet := sqlbuilder.SqlUpdateFieldsSnippet(updateFields)
tx := repository.transactionContext.PgTx
if table.Identify() == nil {
... ... @@ -64,7 +64,6 @@ func (repository *TableRepository) Save(table *domain.Table) (*domain.Table, err
&table.Version,
),
fmt.Sprintf("INSERT INTO metadata.tables (%s) VALUES (%s) RETURNING %s", insertFieldsSnippet, insertPlaceHoldersSnippet, returningFieldsSnippet),
table.TableId,
table.TableType,
table.Name,
table.SQLName,
... ... @@ -75,7 +74,6 @@ func (repository *TableRepository) Save(table *domain.Table) (*domain.Table, err
table.ManualFields,
table.CreatedAt,
table.UpdatedAt,
table.DeletedAt,
table.Version,
); err != nil {
return table, err
... ... @@ -100,7 +98,6 @@ func (repository *TableRepository) Save(table *domain.Table) (*domain.Table, err
&table.Version,
),
fmt.Sprintf("UPDATE metadata.tables SET %s WHERE table_id=? and version=? RETURNING %s", updateFieldsSnippet, returningFieldsSnippet),
table.TableId,
table.TableType,
table.Name,
table.SQLName,
... ... @@ -111,7 +108,6 @@ func (repository *TableRepository) Save(table *domain.Table) (*domain.Table, err
table.ManualFields,
table.CreatedAt,
table.UpdatedAt,
table.DeletedAt,
table.Version,
oldVersion,
table.Identify(),
... ... @@ -134,7 +130,7 @@ func (repository *TableRepository) FindOne(queryOptions map[string]interface{})
tx := repository.transactionContext.PgTx
tableModel := new(models.Table)
query := sqlbuilder.BuildQuery(tx.Model(tableModel), queryOptions)
query.SetWhereByQueryOption("table.table_id = ?", "tableId")
query.SetWhereByQueryOption("table_id = ?", "tableId")
if err := query.First(); err != nil {
if err.Error() == "pg: no rows in result set" {
return nil, fmt.Errorf("没有此资源")
... ...
package utils
import (
"bytes"
"encoding/json"
"fmt"
"github.com/beego/beego/v2/core/validation"
"github.com/bwmarrin/snowflake"
jsonlib "github.com/linmadan/egglib-go/utils/json"
"github.com/shopspring/decimal"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"io"
"io/ioutil"
"reflect"
"strconv"
"strings"
"time"
)
func CamelCase(name string, firstUpper bool) string {
array := []byte(name)
if len(array) == 0 {
return ""
}
rspArray := make([]byte, len(array))
if firstUpper {
copy(rspArray[:1], strings.ToUpper(string(array[:1])))
} else {
copy(rspArray[:1], strings.ToLower(string(array[:1])))
}
copy(rspArray[1:], array[1:])
return string(rspArray)
}
func ObjectToMap(o interface{}) map[string]interface{} {
if o == nil {
return nil
}
value := reflect.ValueOf(o)
if value.Kind() != reflect.Ptr {
return nil
}
elem := value.Elem()
relType := elem.Type()
m := make(map[string]interface{})
for i := 0; i < relType.NumField(); i++ {
field := relType.Field(i)
if elem.Field(i).IsZero() {
continue
}
m[CamelCase(field.Name, false)] = elem.Field(i).Interface()
}
return m
}
func ToMap(o interface{}) map[string]interface{} {
if o == nil {
return nil
}
m := make(map[string]interface{})
data, _ := json.Marshal(o)
json.Unmarshal(data, &m)
return m
}
func DeleteMapKeys(options map[string]interface{}, keys ...string) map[string]interface{} {
for i := range keys {
if _, ok := options[keys[i]]; ok {
delete(options, keys[i])
}
}
return options
}
// AssertString convert v to string value
func AssertString(v interface{}) string {
if v == nil {
return ""
}
// if func (v *Type) String() string, we can't use Elem()
switch vt := v.(type) {
case fmt.Stringer:
return vt.String()
}
val := reflect.ValueOf(v)
if val.Kind() == reflect.Ptr && !val.IsNil() {
val = val.Elem()
}
switch vt := val.Interface().(type) {
case bool:
return strconv.FormatBool(vt)
case error:
return vt.Error()
case float32:
return strconv.FormatFloat(float64(vt), 'f', -1, 32)
case float64:
return strconv.FormatFloat(vt, 'f', -1, 64)
case fmt.Stringer:
return vt.String()
case int:
return strconv.Itoa(vt)
case int8:
return strconv.Itoa(int(vt))
case int16:
return strconv.Itoa(int(vt))
case int32:
return strconv.Itoa(int(vt))
case int64:
return strconv.FormatInt(vt, 10)
case string:
return vt
case uint:
return strconv.FormatUint(uint64(vt), 10)
case uint8:
return strconv.FormatUint(uint64(vt), 10)
case uint16:
return strconv.FormatUint(uint64(vt), 10)
case uint32:
return strconv.FormatUint(uint64(vt), 10)
case uint64:
return strconv.FormatUint(vt, 10)
case []byte:
return string(vt)
default:
return fmt.Sprint(val.Interface())
}
}
// ValidatePtr validate v is a ptr value
func ValidatePtr(v *reflect.Value) error {
// sequence is very important, IsNil must be called after checking Kind() with reflect.Ptr,
// panic otherwise
if !v.IsValid() || v.Kind() != reflect.Ptr || v.IsNil() {
return fmt.Errorf("not a valid pointer: %v", v)
}
return nil
}
func LoadCustomFieldToMap(src interface{}, fields ...string) map[string]interface{} {
rsp := LoadCustomField(src, fields...)
if rsp == nil {
return map[string]interface{}{}
}
return rsp.(map[string]interface{})
}
func LoadCustomField(src interface{}, fields ...string) interface{} {
typeSrc := reflect.TypeOf(src)
valueSrc := reflect.ValueOf(src)
if v, ok := src.(reflect.Value); ok {
valueSrc = v
typeSrc = v.Type()
}
if typeSrc.Kind() == reflect.Ptr {
valueSrc = valueSrc.Elem()
}
k := valueSrc.Kind()
switch k {
case reflect.Array, reflect.Slice:
len := valueSrc.Len()
retSliceMap := make([]map[string]interface{}, 0)
if len == 0 {
return retSliceMap
}
for i := 0; i < len; i++ {
v := valueSrc.Index(i)
retSliceMap = append(retSliceMap, (LoadCustomField(v, fields...)).(map[string]interface{}))
}
return retSliceMap
case reflect.Struct:
retSliceMap := make(map[string]interface{})
for _, filed := range fields {
f := valueSrc.FieldByName(filed)
if !f.IsValid() {
continue
}
v := f.Interface()
if t, ok := v.(time.Time); ok {
v = t.Local().Format("2006-01-02 15:04:05")
}
retSliceMap[CamelCase(filed, false)] = v
}
return retSliceMap
default:
return src
}
return src
}
func AppendCustomField(src interface{}, options map[string]interface{}) interface{} {
var mapSrc map[string]interface{}
var ok bool
mapSrc, ok = src.(map[string]interface{})
if !ok {
jsonlib.Unmarshal([]byte(jsonlib.MarshalToString(src)), &mapSrc)
}
for field, value := range options {
mapSrc[CamelCase(field, false)] = value
}
return mapSrc
}
/*
json 格式化
*/
func Marshal(v interface{}) ([]byte, error) {
return json.Marshal(v)
}
func Unmarshal(data []byte, v interface{}) error {
decoder := json.NewDecoder(bytes.NewReader(data))
if err := unmarshalUseNumber(decoder, v); err != nil {
return formatError(string(data), err)
}
return nil
}
func UnmarshalFromString(str string, v interface{}) error {
decoder := json.NewDecoder(strings.NewReader(str))
if err := unmarshalUseNumber(decoder, v); err != nil {
return formatError(str, err)
}
return nil
}
func UnmarshalFromReader(reader io.Reader, v interface{}) error {
var buf strings.Builder
teeReader := io.TeeReader(reader, &buf)
decoder := json.NewDecoder(teeReader)
if err := unmarshalUseNumber(decoder, v); err != nil {
return formatError(buf.String(), err)
}
return nil
}
func unmarshalUseNumber(decoder *json.Decoder, v interface{}) error {
decoder.UseNumber()
return decoder.Decode(v)
}
func formatError(v string, err error) error {
return fmt.Errorf("string: `%s`, error: `%s`", v, err.Error())
}
type ReflectVal struct {
T reflect.Type
V reflect.Value
}
/*
拷贝当前对象到目标对象,具有相同属性的值
*/
func CopyObject(src, dst interface{}) {
var srcMap = make(map[string]ReflectVal)
vs := reflect.ValueOf(src)
ts := reflect.TypeOf(src)
vd := reflect.ValueOf(dst)
td := reflect.TypeOf(dst)
ls := vs.Elem().NumField()
for i := 0; i < ls; i++ {
srcMap[ts.Elem().Field(i).Name] = ReflectVal{
T: vs.Elem().Field(i).Type(),
V: vs.Elem().Field(i),
}
}
ld := vd.Elem().NumField()
for i := 0; i < ld; i++ {
n := td.Elem().Field(i).Name
t := vd.Elem().Field(i).Type()
if v, ok := srcMap[n]; ok && v.T == t && vd.Elem().Field(i).CanSet() {
vd.Elem().Field(i).Set(v.V)
}
}
}
/*
时间计算
*/
func ValidWorkTime(t string) error {
ts := strings.Split(t, ":")
if len(ts) != 2 {
return fmt.Errorf("时间格式有误")
}
ts1, err := strconv.Atoi(ts[0])
if err != nil {
return fmt.Errorf("小时格式有误")
}
if !(ts1 < 24 && ts1 >= 0) {
return fmt.Errorf("小时格式有误")
}
ts2, err := strconv.Atoi(ts[1])
if err != nil {
return fmt.Errorf("分钟格式有误")
}
if !(ts2 < 60 && ts2 >= 0) {
return fmt.Errorf("分钟格式有误")
}
return nil
}
// 计算两个时间间隔的时间
func ComputeTimeDuration(t1, t2 string) (result time.Duration, err error) {
if err = ValidWorkTime(t1); err != nil {
return
}
if err = ValidWorkTime(t2); err != nil {
return
}
t1s := strings.Split(t1, ":")
t1sHour, _ := strconv.Atoi(t1s[0])
t1sMin, _ := strconv.Atoi(t1s[1])
t2s := strings.Split(t2, ":")
t2sHour, _ := strconv.Atoi(t2s[0])
t2sMin, _ := strconv.Atoi(t2s[1])
var t1t, t2t time.Time
if t1sHour < t2sHour {
t1t = time.Date(2006, 1, 1, t1sHour, t1sMin, 0, 0, time.Local)
t2t = time.Date(2006, 1, 1, t2sHour, t2sMin, 0, 0, time.Local)
} else {
t1t = time.Date(2006, 1, 1, t1sHour, t1sMin, 0, 0, time.Local)
t2t = time.Date(2006, 1, 2, t2sHour, t2sMin, 0, 0, time.Local)
}
ts := t2t.Sub(t1t)
return ts, nil
}
func ToArrayString(inputs []int) []string {
result := make([]string, 0)
for i := range inputs {
result = append(result, strconv.Itoa(inputs[i]))
}
return result
}
func ToArrayInt(inputs []string) []int {
result := make([]int, 0)
for i := range inputs {
v, _ := strconv.Atoi(inputs[i])
result = append(result, v)
}
return result
}
func LoadQueryObject(queryOption map[string]interface{}, obj interface{}) error {
jsonlib.UnmarshalFromString(jsonlib.MarshalToString(queryOption), obj)
validation := validation.Validation{}
result, err := validation.Valid(obj)
if !result && len(validation.Errors) > 0 {
return validation.Errors[0]
}
return err
}
// 字符串截取
func SubStr(str string, start, length int) string {
rs := []rune(str)
rl := len(rs)
end := 0
if start < 0 {
start = rl - 1 + start
}
end = start + length
if start > end {
start, end = end, start
}
if start < 0 {
start = 0
}
if start > rl {
start = rl
}
if end < 0 {
end = 0
}
if end > rl {
end = rl
}
return string(rs[start:end])
}
//生成新ID
var snowFlakeNode *snowflake.Node
func NewSnowflakeId() (int64, error) {
if snowFlakeNode == nil {
node, err := snowflake.NewNode(1)
if err != nil {
return 0, err
}
snowFlakeNode = node
}
// Generate a snowflake ID.
id := snowFlakeNode.Generate()
return id.Int64(), nil
}
// Round 保留数值的精度位 四舍五入
func Round(value float64, places int32) float64 {
quantity := decimal.NewFromFloat(value)
d := quantity.Round(places)
rsp, _ := d.Float64()
return rsp
}
// Truncate 截取数值固定长度的 eg:Truncate(99.99,1) Result: 99.9
func Truncate(value float64, places int32) float64 {
quantity := decimal.NewFromFloat(value).Truncate(places)
rsp, _ := quantity.Float64()
return rsp
}
func Utf8ToGbk(s []byte) ([]byte, error) {
reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewEncoder())
d, e := ioutil.ReadAll(reader)
if e != nil {
return nil, e
}
return d, nil
}
func GbkToUtf8(s []byte) ([]byte, error) {
reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewDecoder())
d, e := ioutil.ReadAll(reader)
if e != nil {
return nil, e
}
return d, nil
}
... ...
package utils
import (
"fmt"
"github.com/stretchr/testify/assert"
"math"
"testing"
"time"
)
func TestTimeSpan(t *testing.T) {
inputs := []struct {
t string
e bool
}{
{"10:00", false},
{"10:11", false},
{"24:00", true},
{"-1:00", true},
{"10:60", true},
{"A:B", true},
}
for i := range inputs {
err := ValidWorkTime(inputs[i].t)
if inputs[i].e {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
}
}
}
func TestComputeTimeDuration(t *testing.T) {
assertDuration := func(s string) time.Duration {
t, _ := time.ParseDuration(s)
return t
}
inputs := []struct {
t1 string
t2 string
ts time.Duration
}{
{
"9:00", "18:00", assertDuration("9h"),
},
{
"23:00", "6:00", assertDuration("7h"),
},
}
for i := range inputs {
input := inputs[i]
out, err := ComputeTimeDuration(input.t1, input.t2)
assert.Nil(t, err)
assert.Equal(t, input.ts, out)
}
}
const TIME_LAYOUT = "2006-01-02 15:04:05"
func TestTimeParse(t *testing.T) {
fmt.Println(int(-1))
timeParse()
}
func timeParse() {
fmt.Println("0. now: ", time.Now())
str := "2018-09-10 16:00:00"
fmt.Println("1. str: ", str)
t, err := time.Parse(TIME_LAYOUT, str)
fmt.Println("2. Parse time: ", t, err)
fmt.Println("2.1. Parse time: ", t.Local(), t.Local().Local())
parseInLocal, _ := time.ParseInLocation(TIME_LAYOUT, str, time.Local)
fmt.Println("2.2 parse in local", parseInLocal, parseInLocal.Local())
tStr := t.Format(TIME_LAYOUT)
fmt.Println("3. Format time str: ", tStr)
name, offset := t.Zone()
name2, offset2 := t.Local().Zone()
fmt.Printf("4. Zone name: %v, Zone offset: %v\n", name, offset)
fmt.Printf("5. Local Zone name: %v, Local Zone offset: %v\n", name2, offset2)
tLocal := t.Local()
tUTC := t.UTC()
fmt.Printf("6. t: %v, Local: %v, UTC: %v\n", t, tLocal, tUTC)
fmt.Printf("7. t: %v, Local: %v, UTC: %v\n", t.Format(TIME_LAYOUT), tLocal.Format(TIME_LAYOUT), tUTC.Format(TIME_LAYOUT))
fmt.Printf("8. Local.Unix: %v, UTC.Unix: %v\n", tLocal.Unix(), tUTC.Unix())
str2 := "1969-12-31 23:59:59"
t2, _ := time.Parse(TIME_LAYOUT, str2)
fmt.Printf("9. str2:%v,time: %v, Unix: %v\n", str2, t2, t2.Unix())
fmt.Printf("10. %v, %v\n", tLocal.Format(time.ANSIC), tUTC.Format(time.ANSIC))
fmt.Printf("11. %v, %v\n", tLocal.Format(time.RFC822), tUTC.Format(time.RFC822))
fmt.Printf("12. %v, %v\n", tLocal.Format(time.RFC822Z), tUTC.Format(time.RFC822Z))
//指定时区
parseWithLocation("America/Cordoba", str)
parseWithLocation("Asia/Shanghai", str)
parseWithLocation("Asia/Beijing", str)
}
func parseWithLocation(name string, timeStr string) (time.Time, error) {
locationName := name
if l, err := time.LoadLocation(locationName); err != nil {
println(err.Error())
return time.Time{}, err
} else {
lt, _ := time.ParseInLocation(TIME_LAYOUT, timeStr, l)
fmt.Println(locationName, lt)
return lt, nil
}
}
func TestRound(t *testing.T) {
t.Logf("%v", Round(99.999, 1))
t.Logf("%v", Round(99.999, 2))
t.Logf("%.1f", math.Floor(99.99))
t.Logf("%v", math.Ceil(99.99))
t.Logf("%.1f", Truncate(99.99, 1))
t.Logf("%v", Truncate(99, 0))
}
... ...
package controllers
import (
"github.com/linmadan/egglib-go/web/beego"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/log/command"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/log/query"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/log/service"
)
type LogController struct {
beego.BaseController
}
func (controller *LogController) CreateLog() {
logService := service.NewLogService(nil)
createLogCommand := &command.CreateLogCommand{}
controller.Unmarshal(createLogCommand)
data, err := logService.CreateLog(createLogCommand)
controller.Response(data, err)
}
func (controller *LogController) UpdateLog() {
logService := service.NewLogService(nil)
updateLogCommand := &command.UpdateLogCommand{}
controller.Unmarshal(updateLogCommand)
logId, _ := controller.GetInt(":logId")
updateLogCommand.LogId = logId
data, err := logService.UpdateLog(updateLogCommand)
controller.Response(data, err)
}
func (controller *LogController) GetLog() {
logService := service.NewLogService(nil)
getLogQuery := &query.GetLogQuery{}
logId, _ := controller.GetInt(":logId")
getLogQuery.LogId = logId
data, err := logService.GetLog(getLogQuery)
controller.Response(data, err)
}
func (controller *LogController) RemoveLog() {
logService := service.NewLogService(nil)
removeLogCommand := &command.RemoveLogCommand{}
controller.Unmarshal(removeLogCommand)
logId, _ := controller.GetInt(":logId")
removeLogCommand.LogId = logId
data, err := logService.RemoveLog(removeLogCommand)
controller.Response(data, err)
}
func (controller *LogController) ListLog() {
logService := service.NewLogService(nil)
listLogQuery := &query.ListLogQuery{}
offset, _ := controller.GetInt("offset")
listLogQuery.Offset = offset
limit, _ := controller.GetInt("limit")
listLogQuery.Limit = limit
data, err := logService.ListLog(listLogQuery)
controller.Response(data, err)
}
func (controller *LogController) SearchLog() {
logService := service.NewLogService(nil)
searchLogCommand := &command.SearchLogCommand{}
controller.Unmarshal(searchLogCommand)
data, err := logService.SearchLog(searchLogCommand)
controller.Response(data, err)
}
... ...
... ... @@ -6,18 +6,17 @@ import (
)
func init() {
web.Router("/bastion/files/", &controllers.FileController{}, "Post:CreateFile")
web.Router("/bastion/files/:fileId", &controllers.FileController{}, "Put:UpdateFile")
web.Router("/bastion/files/:fileId", &controllers.FileController{}, "Get:GetFile")
web.Router("/bastion/files/:fileId", &controllers.FileController{}, "Delete:RemoveFile")
web.Router("/bastion/files/", &controllers.FileController{}, "Get:ListFile")
web.Router("/bastion/files/search", &controllers.FileController{}, "Post:SearchFile")
web.Router("/bastion/files/search", &controllers.FileController{}, "Post:SearchFile")
web.Router("/bastion/files/search-source-file", &controllers.FileController{}, "Post:SearchSourceFile")
web.Router("/bastion/files/search-verified-file", &controllers.FileController{}, "Post:SearchVerifiedFile")
web.Router("/data/files/", &controllers.FileController{}, "Post:CreateFile")
web.Router("/data/files/:fileId", &controllers.FileController{}, "Put:UpdateFile")
web.Router("/data/files/:fileId", &controllers.FileController{}, "Get:GetFile")
web.Router("/data/files/:fileId", &controllers.FileController{}, "Delete:RemoveFile")
web.Router("/data/files/", &controllers.FileController{}, "Get:ListFile")
web.Router("/data/files/search", &controllers.FileController{}, "Post:SearchFile")
web.Router("/data/files/search-source-file", &controllers.FileController{}, "Post:SearchSourceFile")
web.Router("/data/files/search-verified-file", &controllers.FileController{}, "Post:SearchVerifiedFile")
web.Router("/bastion/load-data-table", &controllers.FileController{}, "Post:LoadDataTable")
web.Router("/bastion/edit-data-table", &controllers.FileController{}, "Post:EditDataTable")
web.Router("/bastion/flush-data-table", &controllers.FileController{}, "Post:FlushDataTable")
web.Router("/bastion/generate-main-table", &controllers.FileController{}, "Post:GenerateMainTable")
web.Router("/data/load-data-table", &controllers.FileController{}, "Post:LoadDataTable")
web.Router("/data/edit-data-table", &controllers.FileController{}, "Post:EditDataTable")
web.Router("/data/flush-data-table", &controllers.FileController{}, "Post:FlushDataTable")
web.Router("/data/generate-main-table", &controllers.FileController{}, "Post:GenerateMainTable")
}
... ...
package routers
import (
"github.com/beego/beego/v2/server/web"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/port/beego/controllers"
)
func init() {
web.Router("/logs/", &controllers.LogController{}, "Post:CreateLog")
web.Router("/logs/:logId", &controllers.LogController{}, "Put:UpdateLog")
web.Router("/logs/:logId", &controllers.LogController{}, "Get:GetLog")
web.Router("/logs/:logId", &controllers.LogController{}, "Delete:RemoveLog")
web.Router("/logs/", &controllers.LogController{}, "Get:ListLog")
web.Router("/logs/search", &controllers.LogController{}, "Post:SearchLog")
}
... ...
package routers
import (
"github.com/beego/beego/v2/server/web"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/constant"
)
func init() {
web.SetStaticPath("/log", constant.LOG_FILE)
}
... ...
package log
import (
"net/http"
"github.com/gavv/httpexpect"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
pG "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/pg"
)
var _ = Describe("创建日志服务", func() {
Describe("提交数据创建日志服务", func() {
Context("提交正确的新日志数据", func() {
It("返回日志数据", func() {
httpExpect := httpexpect.New(GinkgoT(), server.URL)
body := map[string]interface{}{
"objectName": "string",
"objectType": "string",
"operationType": "string",
"content": "string",
"operatorName": "string",
}
httpExpect.POST("/logs/").
WithJSON(body).
Expect().
Status(http.StatusOK).
JSON().
Object().
ContainsKey("code").ValueEqual("code", 0).
ContainsKey("msg").ValueEqual("msg", "ok").
ContainsKey("data").Value("data").Object().
ContainsKey("logId").ValueNotEqual("logId", BeZero())
})
})
})
AfterEach(func() {
_, err := pG.DB.Exec("DELETE FROM logs WHERE true")
Expect(err).NotTo(HaveOccurred())
})
})
... ...
package log
import (
"github.com/go-pg/pg/v10"
"net/http"
"github.com/gavv/httpexpect"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
pG "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/pg"
)
var _ = Describe("返回日志服务", func() {
var logId int64
BeforeEach(func() {
_, err := pG.DB.QueryOne(
pg.Scan(&logId),
"INSERT INTO logs (log_id, log_type, source_id, entry, created_at) VALUES (?, ?, ?, ?, ?) RETURNING log_id",
"testLogId", "testLogType", "testSourceId", "testEntry", "testCreatedAt")
Expect(err).NotTo(HaveOccurred())
})
Describe("根据logId参数返回日志", func() {
Context("传入有效的logId", func() {
It("返回日志数据", func() {
httpExpect := httpexpect.New(GinkgoT(), server.URL)
httpExpect.GET("/logs/{logId}").
Expect().
Status(http.StatusOK).
JSON().
Object().
ContainsKey("code").ValueEqual("code", 0).
ContainsKey("msg").ValueEqual("msg", "ok").
ContainsKey("data").Value("data").Object()
})
})
})
AfterEach(func() {
_, err := pG.DB.Exec("DELETE FROM logs WHERE true")
Expect(err).NotTo(HaveOccurred())
})
})
... ...
package log
import (
"github.com/go-pg/pg/v10"
"net/http"
"github.com/gavv/httpexpect"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
pG "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/pg"
)
var _ = Describe("返回日志服务列表", func() {
var logId int64
BeforeEach(func() {
_, err := pG.DB.QueryOne(
pg.Scan(&logId),
"INSERT INTO logs (log_id, log_type, source_id, entry, created_at) VALUES (?, ?, ?, ?, ?) RETURNING log_id",
"testLogId", "testLogType", "testSourceId", "testEntry", "testCreatedAt")
Expect(err).NotTo(HaveOccurred())
})
Describe("根据参数返回日志列表", func() {
Context("传入有效的参数", func() {
It("返回日志数据列表", func() {
httpExpect := httpexpect.New(GinkgoT(), server.URL)
httpExpect.GET("/logs/").
WithQuery("offset", "int").
WithQuery("limit", "int").
Expect().
Status(http.StatusOK).
JSON().
Object().
ContainsKey("code").ValueEqual("code", 0).
ContainsKey("msg").ValueEqual("msg", "ok").
ContainsKey("data").Value("data").Object().
ContainsKey("count").ValueEqual("count", 1).
ContainsKey("logs").Value("logs").Array()
})
})
})
AfterEach(func() {
_, err := pG.DB.Exec("DELETE FROM logs WHERE true")
Expect(err).NotTo(HaveOccurred())
})
})
... ...
package log
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/beego/beego/v2/server/web"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
_ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application"
_ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/pg"
_ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/port/beego"
)
func TestLog(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Beego Port Log Correlations Test Case Suite")
}
var handler http.Handler
var server *httptest.Server
var _ = BeforeSuite(func() {
handler = web.BeeApp.Handlers
server = httptest.NewServer(handler)
})
var _ = AfterSuite(func() {
server.Close()
})
... ...
package log
import (
"github.com/go-pg/pg/v10"
"net/http"
"github.com/gavv/httpexpect"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
pG "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/pg"
)
var _ = Describe("移除日志服务", func() {
var logId int64
BeforeEach(func() {
_, err := pG.DB.QueryOne(
pg.Scan(&logId),
"INSERT INTO logs (log_id, log_type, source_id, entry, created_at) VALUES (?, ?, ?, ?, ?) RETURNING log_id",
"testLogId", "testLogType", "testSourceId", "testEntry", "testCreatedAt")
Expect(err).NotTo(HaveOccurred())
})
Describe("根据参数移除日志服务", func() {
Context("传入有效的logId", func() {
It("返回被移除日志的数据", func() {
httpExpect := httpexpect.New(GinkgoT(), server.URL)
httpExpect.DELETE("/logs/{logId}").
Expect().
Status(http.StatusOK).
JSON().
Object().
ContainsKey("code").ValueEqual("code", 0).
ContainsKey("msg").ValueEqual("msg", "ok").
ContainsKey("data").Value("data").Object()
})
})
})
AfterEach(func() {
_, err := pG.DB.Exec("DELETE FROM logs WHERE true")
Expect(err).NotTo(HaveOccurred())
})
})
... ...
package log
import (
"github.com/go-pg/pg/v10"
"net/http"
"github.com/gavv/httpexpect"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
pG "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/pg"
)
var _ = Describe("搜索日志", func() {
var logId int64
BeforeEach(func() {
_, err := pG.DB.QueryOne(
pg.Scan(&logId),
"INSERT INTO logs (log_id, log_type, source_id, entry, created_at) VALUES (?, ?, ?, ?, ?) RETURNING log_id",
"testLogId", "testLogType", "testSourceId", "testEntry", "testCreatedAt")
Expect(err).NotTo(HaveOccurred())
})
Describe("搜索日志", func() {
Context("", func() {
It("", func() {
httpExpect := httpexpect.New(GinkgoT(), server.URL)
body := map[string]interface{}{
"content": "string",
}
httpExpect.POST("/logs/search").
WithJSON(body).
Expect().
Status(http.StatusOK).
JSON().
Object().
ContainsKey("code").ValueEqual("code", 0).
ContainsKey("msg").ValueEqual("msg", "ok").
ContainsKey("data").Value("data").Object()
})
})
})
AfterEach(func() {
_, err := pG.DB.Exec("DELETE FROM logs WHERE true")
Expect(err).NotTo(HaveOccurred())
})
})
... ...
package log
import (
"github.com/go-pg/pg/v10"
"net/http"
"github.com/gavv/httpexpect"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
pG "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/pg"
)
var _ = Describe("更新日志服务", func() {
var logId int64
BeforeEach(func() {
_, err := pG.DB.QueryOne(
pg.Scan(&logId),
"INSERT INTO logs (log_id, log_type, source_id, entry, created_at) VALUES (?, ?, ?, ?, ?) RETURNING log_id",
"testLogId", "testLogType", "testSourceId", "testEntry", "testCreatedAt")
Expect(err).NotTo(HaveOccurred())
})
Describe("提交数据更新日志服务", func() {
Context("提交正确的日志数据", func() {
It("返回更新后的日志数据", func() {
httpExpect := httpexpect.New(GinkgoT(), server.URL)
body := map[string]interface{}{}
httpExpect.PUT("/logs/{logId}").
WithJSON(body).
Expect().
Status(http.StatusOK).
JSON().
Object().
ContainsKey("code").ValueEqual("code", 0).
ContainsKey("msg").ValueEqual("msg", "ok").
ContainsKey("data").Value("data").Object().
ContainsKey("logId").ValueEqual("logId", logId)
})
})
})
AfterEach(func() {
_, err := pG.DB.Exec("DELETE FROM logs WHERE true")
Expect(err).NotTo(HaveOccurred())
})
})
... ...