作者 yangfu

fix:check table row duplicate

... ... @@ -10,9 +10,9 @@ import (
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/table/dto"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/table/query"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/redis"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/starrocks"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/utils"
"strconv"
"strings"
)
... ... @@ -433,9 +433,9 @@ func (tableService *TableService) ValidExprSql(ctx *domain.Context, cmd *command
set.AddStr(f.TableSqlName)
}
selectValue := cmd.ExprSql
if _, parseErr := strconv.ParseFloat(cmd.ExprSql, 64); parseErr != nil {
selectValue = "'" + selectValue + "'"
}
//if _, parseErr := strconv.ParseFloat(cmd.ExprSql, 64); parseErr != nil {
// selectValue = "'" + selectValue + "'"
//}
sql := "select " + selectValue + " as expr"
if len(set.KeysStr()) > 0 {
sql += " from " + strings.Join(set.KeysStr(), ",")
... ... @@ -551,6 +551,127 @@ func (tableService *TableService) CheckRowDuplicateV2(ctx *domain.Context, cmd *
}, nil
}
func (tableService *TableService) CheckRowDuplicateV3(ctx *domain.Context, cmd *command.CheckRowDuplicateCommand) (interface{}, error) {
var defaultResponse = map[string]interface{}{
"rowDuplicateFlag": false,
}
if cmd.TableId == 0 {
return defaultResponse, nil
}
if err := cmd.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 table *domain.Table
_, table, err = factory.FastPgTable(transactionContext, cmd.TableId)
if err != nil {
return nil, factory.FastError(err)
}
querySetRepository, _, _ := factory.FastPgQuerySet(transactionContext, 0)
querySet, _ := querySetRepository.FindOne(map[string]interface{}{"BindTableId": table.TableId, "context": ctx})
if querySet == nil {
cache := redis.NewTableQuerySetCacheService()
if item, cacheItemErr := cache.GetTableQuerySetCache(redis.KeyTableQuerySet(cmd.TableId)); cacheItemErr == nil {
querySet = &domain.QuerySet{QuerySetId: item.QuerySetId, QueryComponents: item.QueryComponents}
}
}
if querySet == nil {
return defaultResponse, nil
}
if len(querySet.QueryComponents) == 1 {
return defaultResponse, nil
}
var mapQueryComponents = make(map[int][]*domain.QueryComponent)
for _, queryComponent := range querySet.QueryComponents {
if _, ok := mapQueryComponents[queryComponent.MasterTable.TableId]; !ok {
mapQueryComponents[queryComponent.MasterTable.TableId] = make([]*domain.QueryComponent, 0)
}
mapQueryComponents[queryComponent.MasterTable.TableId] = append(mapQueryComponents[queryComponent.MasterTable.TableId], queryComponent)
}
for _, v := range mapQueryComponents {
if len(v) <= 1 {
continue
}
total, duplicateTotal, err := starrocks.WrapQueryHasDuplicateRowBySql(CountQueryComponents(v), starrocks.DB)()
if err != nil {
return nil, factory.FastError(err)
}
if total != duplicateTotal {
return map[string]interface{}{
"tableName": table.Name,
"rowDuplicateFlag": total != duplicateTotal,
"rowTotal": total,
"rowDuplicateTotal": total - duplicateTotal,
}, nil
}
}
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return defaultResponse, nil
}
func CountQueryComponents(queryComponents []*domain.QueryComponent) string {
var sql = "select count(id) c1,count(DISTINCT(id)) c2 from ("
for _, q := range queryComponents {
sql += "\n"
sql += ViewQueryComponent(q)
sql += "\n"
sql += "union all"
}
sql = strings.TrimSuffix(sql, "union all")
sql += ") a"
return sql
}
func ViewQueryComponent(queryComponent *domain.QueryComponent) string {
sql := "select * from " + queryComponent.MasterTable.SQLName
for i, c := range queryComponent.Conditions {
if i == 0 {
sql += " where "
}
if len(c.FieldRight.TableFields) > 0 && queryComponent.MasterTable.TableId != c.FieldRight.TableFields[0].TableId {
continue
}
sql += FormatCondition(c)
sql += " and"
}
sql = strings.TrimSuffix(sql, "and")
return sql
}
func FormatCondition(c domain.ConditionExpr) string {
//if len(c.FieldRight.TableFields) > 0 {
// return fmt.Sprintf("%s %s %s", c.FieldRight.ExprSql, FormatOp(c.OperatorSymbol), FormatByOp(c.OperatorSymbol, c.FieldRight.ExprSql))
//}
//if domain.SQLType(c.FieldLeft.TableFields[0].FieldSQLType).IsString() {
// return fmt.Sprintf("%s %s '%s'", c.FieldRight.ExprSql, FormatOp(c.OperatorSymbol), FormatByOp(c.OperatorSymbol, c.FieldRight.ExprSql))
//}
return fmt.Sprintf("%s %s %s", c.FieldLeft.ExprSql, FormatOp(c.OperatorSymbol), FormatByOp(c.OperatorSymbol, c.FieldRight.ExprSql))
}
func FormatOp(op string) string {
return op
}
func FormatByOp(op string, exprSql string) string {
return exprSql
}
func NewTableService(options map[string]interface{}) *TableService {
newTableService := &TableService{}
return newTableService
... ...
... ... @@ -5,6 +5,7 @@ import (
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/redis"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/repository"
"strings"
"time"
... ... @@ -148,6 +149,7 @@ func (ptr *QuerySetService) PreviewPrepare(ctx *domain.Context, querySetId int,
return t, nil
}
}
// 验证
if err = ptr.validQueryComponents(queryComponents); err != nil {
return nil, err
... ... @@ -178,7 +180,11 @@ func (ptr *QuerySetService) PreviewPrepare(ctx *domain.Context, querySetId int,
if err != nil {
return nil, err
}
// set cache
cache := redis.NewTableQuerySetCacheService()
if err = cache.SetTableQuerySetCache(redis.KeyTableQuerySet(table.TableId), redis.NewTableQuerySetCache(querySet.QuerySetId, table.TableId, queryComponents)); err != nil {
return nil, err
}
// 调用底层的组装sql
if _, err = ByteCore.FormulasGenerate(domain.ReqFormulasGenerate{
QuerySet: querySet,
... ... @@ -346,7 +352,19 @@ func conditionsEditLog(ctx *domain.Context, querySet *domain.QuerySet, queryComp
func queryComponentsHasEdit(ctx *domain.Context, querySet *domain.QuerySet, queryComponents []*domain.QueryComponent) bool {
logs := selectsEditLog(ctx, querySet, queryComponents)
return len(logs) != 0
if len(logs) > 0 {
return true
}
logs = conditionsEditLog(ctx, querySet, queryComponents)
if len(logs) > 0 {
return true
}
for _, item := range queryComponents {
if len(item.Id) == 0 {
return true
}
}
return false
}
func selectsEditLog(ctx *domain.Context, querySet *domain.QuerySet, queryComponents []*domain.QueryComponent) []FastSourceLog {
... ...
package redis
import (
"fmt"
"github.com/linmadan/egglib-go/utils/json"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/constant"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
)
const (
TableQuerySetExpire = 3600 * 24
)
func KeyTableQuerySet(tableId int) string {
return fmt.Sprintf("%v:queryset:temporary:%v", constant.CACHE_PREFIX, tableId)
}
type TableQuerySetCache struct {
QuerySetId int `json:"querySetId"`
TableId int `json:"tableId"`
QueryComponents []*domain.QueryComponent `json:"queryComponents"`
}
func NewTableQuerySetCache(querySetId int, tableId int, queryComponents []*domain.QueryComponent) TableQuerySetCache {
return TableQuerySetCache{
QuerySetId: querySetId,
TableId: tableId,
QueryComponents: queryComponents,
}
}
type TableQuerySetCacheService struct {
}
func (s *TableQuerySetCacheService) SetTableQuerySetCache(key string, cache TableQuerySetCache) error {
err := ZeroCoreRedis.Setex(key, json.MarshalToString(cache), TemporaryFileExpire)
return err
}
func (s *TableQuerySetCacheService) GetTableQuerySetCache(key string) (*TableQuerySetCache, error) {
var res = &TableQuerySetCache{}
ok, err := ZeroCoreRedis.Exists(key)
if !ok {
return nil, domain.ErrorNotFound
}
if err != nil {
return nil, err
}
data, err := ZeroCoreRedis.Get(key)
if err != nil {
return nil, err
}
err = json.UnmarshalFromString(data, res)
if err != nil {
return nil, err
}
return res, nil
}
func NewTableQuerySetCacheService() *TableQuerySetCacheService {
return &TableQuerySetCacheService{}
}
... ...
... ... @@ -367,3 +367,22 @@ func WrapQueryHasDuplicateRowByIDWithDB(params QueryOptions, db *gorm.DB) func()
return total, duplicateTotal, nil
}
}
func WrapQueryHasDuplicateRowBySql(sql string, db *gorm.DB) func() (int64, int64, error) {
return func() (int64, int64, error) {
var total int64
var duplicateTotal int64
query := db.Raw(sql)
row := query.Row()
if row.Err() != nil {
return total, duplicateTotal, row.Err()
}
if err := row.Scan(&total, &duplicateTotal); err != nil {
return total, duplicateTotal, err
}
if total == duplicateTotal {
return total, duplicateTotal, nil
}
return total, duplicateTotal, nil
}
}
... ...
... ... @@ -187,7 +187,7 @@ func (controller *TableController) CheckRowDuplicate() {
tableService := service.NewTableService(nil)
cmd := &command.CheckRowDuplicateCommand{}
Must(controller.Unmarshal(cmd))
data, err := tableService.CheckRowDuplicateV2(ParseContext(controller.BaseController), cmd)
data, err := tableService.CheckRowDuplicateV3(ParseContext(controller.BaseController), cmd)
controller.Response(data, err)
}
... ...