|
|
package domainService
|
|
|
|
|
|
import (
|
|
|
"fmt"
|
|
|
"github.com/zeromicro/go-zero/core/collection"
|
|
|
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
|
|
|
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/repository"
|
|
|
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/starrocks"
|
|
|
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/log"
|
|
|
"strings"
|
|
|
)
|
|
|
|
|
|
const DefaultExpandNum = 10000
|
|
|
const MaxExpandNum = 50000
|
|
|
|
|
|
func (ptr *QuerySetService) LoadCalculateSetData(ctx *domain.Context, qs *domain.QuerySet, queryComponents []*domain.QueryComponent) (*domain.DataTable, error) {
|
|
|
var (
|
|
|
res = &domain.DataTable{}
|
|
|
dataTables = make(map[int]*domain.DataTable)
|
|
|
err error
|
|
|
)
|
|
|
|
|
|
if len(queryComponents) == 0 {
|
|
|
return res, nil
|
|
|
}
|
|
|
// 加载Tables数据
|
|
|
q := queryComponents[0]
|
|
|
cells := q.Layout.LayoutCells()
|
|
|
dataTables = ptr.LoadDataTables(ctx, cells)
|
|
|
// 数据布局
|
|
|
res, err = DataLayout(res, dataTables, cells)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
// 数据持久化
|
|
|
return res, nil
|
|
|
}
|
|
|
|
|
|
func FastTable(table *domain.Table) (*domain.DataTable, error) {
|
|
|
var err error
|
|
|
var options = starrocks.QueryOptions{
|
|
|
Table: table,
|
|
|
TableName: table.SQLName,
|
|
|
Select: table.Fields(false),
|
|
|
}
|
|
|
var dataTable *domain.DataTable
|
|
|
dataTable, err = FastDataTable(options)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return dataTable, nil
|
|
|
}
|
|
|
|
|
|
func FastDataTable(options starrocks.QueryOptions) (*domain.DataTable, error) {
|
|
|
var err error
|
|
|
// 待优化分批下载,压缩
|
|
|
var dataTable *domain.DataTable
|
|
|
dataTable, err = starrocks.Query(options, starrocks.WrapQueryFuncWithDB(starrocks.DB))
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
dataTable.Total, err = starrocks.WrapQueryCountWithDB(options, starrocks.DB)()
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return dataTable, nil
|
|
|
}
|
|
|
|
|
|
func (ptr *QuerySetService) LoadDataTables(ctx *domain.Context, cells []*domain.LayoutCell) map[int]*domain.DataTable {
|
|
|
var (
|
|
|
dataTables = make(map[int]*domain.DataTable)
|
|
|
tableRepository, _ = repository.NewTableRepository(ptr.transactionContext)
|
|
|
)
|
|
|
tableIds := collection.NewSet()
|
|
|
for _, cell := range cells {
|
|
|
if cell.Data == nil || cell.Data.TableField == nil || cell.Data.TableField.TableId == 0 {
|
|
|
continue
|
|
|
}
|
|
|
tableIds.AddInt(cell.Data.TableField.TableId)
|
|
|
}
|
|
|
if len(tableIds.KeysInt()) > 0 {
|
|
|
_, tables, err := tableRepository.Find(map[string]interface{}{"context": ctx, "tableIds": tableIds.KeysInt()})
|
|
|
if err != nil {
|
|
|
return nil
|
|
|
}
|
|
|
for _, t := range tables {
|
|
|
if _, ok := dataTables[t.TableId]; ok {
|
|
|
continue
|
|
|
}
|
|
|
dataTable, e := FastTable(t)
|
|
|
if e != nil {
|
|
|
log.Logger.Error(e.Error())
|
|
|
continue
|
|
|
}
|
|
|
dataTable.Fields = t.DataFields
|
|
|
dataTables[t.TableId] = dataTable
|
|
|
}
|
|
|
}
|
|
|
return dataTables
|
|
|
}
|
|
|
|
|
|
func DataLayout(res *domain.DataTable, dataTables map[int]*domain.DataTable, cells []*domain.LayoutCell) (*domain.DataTable, error) {
|
|
|
dt := &DataLayoutDataTable{
|
|
|
DataTable: res,
|
|
|
MapDataTables: dataTables,
|
|
|
unprocessed: cells,
|
|
|
}
|
|
|
dt.Init(DefaultExpandNum)
|
|
|
for {
|
|
|
if len(dt.unprocessed) == 0 {
|
|
|
break
|
|
|
}
|
|
|
cell := dt.unprocessed[0]
|
|
|
dt.unprocessed = dt.unprocessed[1:]
|
|
|
blockData, length := dt.BlockData(cell)
|
|
|
if err := dt.Expand(cell, length); err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
dt.addByLocation(cell, blockData)
|
|
|
// 当前单元格子 影响其他格子坐标
|
|
|
dt.changeUnProcessedLocation(cell, length)
|
|
|
dt.processed = append(dt.processed, cell)
|
|
|
dt.LastCell = cell
|
|
|
}
|
|
|
dt.Shrink()
|
|
|
return dt.DataTable, nil
|
|
|
}
|
|
|
|
|
|
type DataLayoutDataTable struct {
|
|
|
PointBegin *Location
|
|
|
PointEnd *Location
|
|
|
MaxX int
|
|
|
MaxY int
|
|
|
DataTable *domain.DataTable
|
|
|
MapDataTables map[int]*domain.DataTable
|
|
|
processed []*domain.LayoutCell
|
|
|
unprocessed []*domain.LayoutCell
|
|
|
LastCell *domain.LayoutCell
|
|
|
}
|
|
|
|
|
|
type Location struct {
|
|
|
X int
|
|
|
Y int
|
|
|
}
|
|
|
|
|
|
func NewLocation(x, y int) *Location {
|
|
|
return &Location{
|
|
|
X: x,
|
|
|
Y: y,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (l *Location) UpdateX(x int) {
|
|
|
if l.X <= x {
|
|
|
l.X = x
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (l *Location) UpdateY(y int) {
|
|
|
if l.Y <= y {
|
|
|
l.Y = y
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (d *DataLayoutDataTable) StartCell() {
|
|
|
|
|
|
}
|
|
|
|
|
|
func (d *DataLayoutDataTable) addByLocation(cell *domain.LayoutCell, blockData []string) {
|
|
|
if d.PointBegin == nil {
|
|
|
d.PointBegin = NewLocation(cell.X, cell.Y)
|
|
|
d.PointEnd = NewLocation(cell.X, cell.Y)
|
|
|
}
|
|
|
switch cell.Direction {
|
|
|
case domain.DirectionRight:
|
|
|
for i := range blockData {
|
|
|
d.DataTable.Data[cell.X][cell.Y+i] = blockData[i]
|
|
|
}
|
|
|
d.PointEnd.UpdateX(cell.X)
|
|
|
d.PointEnd.UpdateY(cell.Y + len(blockData) - 1)
|
|
|
case domain.DirectionDown:
|
|
|
for i := range blockData {
|
|
|
d.DataTable.Data[cell.X+i][cell.Y] = blockData[i]
|
|
|
}
|
|
|
d.PointEnd.UpdateX(cell.X + len(blockData) - 1)
|
|
|
d.PointEnd.UpdateY(cell.Y)
|
|
|
case domain.DirectionNone:
|
|
|
d.DataTable.Data[cell.X][cell.Y] = blockData[0]
|
|
|
d.PointEnd.UpdateX(cell.X)
|
|
|
d.PointEnd.UpdateY(cell.Y)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (d *DataLayoutDataTable) changeUnProcessedLocation(lastCell *domain.LayoutCell, length int) {
|
|
|
// log.Logger.Info("修改定位点")
|
|
|
for _, cell := range d.unprocessed {
|
|
|
switch lastCell.Direction {
|
|
|
case domain.DirectionRight:
|
|
|
if cell.X >= lastCell.X && cell.Y > lastCell.Y {
|
|
|
cell.Y += length - 1
|
|
|
}
|
|
|
case domain.DirectionDown:
|
|
|
if cell.X > lastCell.X && cell.Y >= lastCell.Y {
|
|
|
cell.X += length - 1
|
|
|
}
|
|
|
}
|
|
|
// log.Logger.Info(fmt.Sprintf("%s %s X:%d Y:%d", cell.Data.Field.SQLName, cell.Direction, cell.X, cell.Y))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (d *DataLayoutDataTable) BlockData(cells *domain.LayoutCell) ([]string, int) {
|
|
|
var block []string
|
|
|
if cells.Type == domain.CellTypeText {
|
|
|
data := []string{cells.Data.Text}
|
|
|
return data, 1
|
|
|
}
|
|
|
table, ok := d.MapDataTables[cells.Data.TableField.TableId]
|
|
|
if !ok {
|
|
|
return block, 0
|
|
|
}
|
|
|
values := table.Values(&domain.Field{SQLName: cells.Data.TableField.FieldSqlName})
|
|
|
if len(values) == 0 {
|
|
|
return block, 0
|
|
|
}
|
|
|
if cells.Data.TableField != nil && strings.HasPrefix(cells.Data.TableField.TableSqlName, strings.ToLower(domain.CalculateItem.ToString())) {
|
|
|
return values[:1], 1
|
|
|
}
|
|
|
if cells.Direction == domain.DirectionNone {
|
|
|
return values[:1], 1
|
|
|
}
|
|
|
return values, len(values)
|
|
|
}
|
|
|
|
|
|
func (d *DataLayoutDataTable) Shrink() {
|
|
|
x := d.PointEnd.X - d.PointBegin.X
|
|
|
y := d.PointEnd.Y - d.PointBegin.Y
|
|
|
data := make([][]string, x+1)
|
|
|
for i := range data {
|
|
|
data[i] = make([]string, y+1)
|
|
|
}
|
|
|
iData := 0
|
|
|
for i := d.PointBegin.X; i <= d.PointEnd.X; i++ {
|
|
|
jData := 0
|
|
|
for j := d.PointBegin.Y; j <= d.PointEnd.Y; j++ {
|
|
|
data[iData][jData] = d.DataTable.Data[i][j]
|
|
|
jData++
|
|
|
}
|
|
|
iData++
|
|
|
}
|
|
|
d.DataTable.Data = data
|
|
|
for i := 0; i <= y; i++ {
|
|
|
d.DataTable.Fields = append(d.DataTable.Fields, &domain.Field{
|
|
|
Name: fmt.Sprintf("列%d", i),
|
|
|
SQLName: fmt.Sprintf("col%d", i),
|
|
|
SQLType: domain.String.ToString(),
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (d *DataLayoutDataTable) Expand(cell *domain.LayoutCell, length int) error {
|
|
|
if !d.CellOutRange(cell, length) {
|
|
|
return nil
|
|
|
}
|
|
|
expandLength := DefaultExpandNum
|
|
|
if expandLength < length {
|
|
|
expandLength = length
|
|
|
}
|
|
|
if d.MaxX+expandLength > MaxExpandNum {
|
|
|
return fmt.Errorf("布局元素超过限制 %d", MaxExpandNum)
|
|
|
}
|
|
|
copyData := make([][]string, d.MaxX+length)
|
|
|
for i := range copyData {
|
|
|
copyData[i] = make([]string, d.MaxY+length)
|
|
|
}
|
|
|
copy(copyData, d.DataTable.Data)
|
|
|
d.DataTable.Data = copyData
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (d *DataLayoutDataTable) Init(length int) {
|
|
|
initData := make([][]string, length)
|
|
|
for i := range initData {
|
|
|
initData[i] = make([]string, length)
|
|
|
}
|
|
|
d.DataTable.Data = initData
|
|
|
d.AddRange(length)
|
|
|
}
|
|
|
|
|
|
func (d *DataLayoutDataTable) AddRange(length int) {
|
|
|
d.MaxY += length
|
|
|
d.MaxX += length
|
|
|
}
|
|
|
|
|
|
func (d *DataLayoutDataTable) CellOutRange(cell *domain.LayoutCell, length int) bool {
|
|
|
if cell.X+length > d.MaxX {
|
|
|
return true
|
|
|
}
|
|
|
if cell.Y+length > d.MaxY {
|
|
|
return true
|
|
|
}
|
|
|
return false
|
|
|
} |
...
|
...
|
|