Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cmd/protoc-gen-cpp-tableau-loader/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,12 @@ func genIndexSorter(g *protogen.GeneratedFile, descriptor *index.IndexDescriptor
for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel {
for _, index := range levelMessage.Indexes {
indexContainerName := "index_" + strcase.ToSnake(index.Name()) + "_map_"
if len(index.KeyFields) != 0 {
if len(index.SortedColFields) != 0 {
g.P(helper.Indent(1), "// Index(sort): ", index.Index)
g.P(helper.Indent(1), "for (auto&& item : ", indexContainerName, ") {")
g.P(helper.Indent(2), "std::sort(item.second.begin(), item.second.end(),")
g.P(helper.Indent(7), "[](const ", helper.ParseCppClassType(index.MD), "* a, const ", helper.ParseCppClassType(index.MD), "* b) {")
for i, field := range index.KeyFields {
for i, field := range index.SortedColFields {
fieldName := ""
for i, leveledFd := range field.LeveledFDList {
accessOperator := "."
Expand All @@ -174,7 +174,7 @@ func genIndexSorter(g *protogen.GeneratedFile, descriptor *index.IndexDescriptor
}
fieldName += accessOperator + helper.ParseIndexFieldName(leveledFd) + "()"
}
if i == len(index.KeyFields)-1 {
if i == len(index.SortedColFields)-1 {
g.P(helper.Indent(8), "return a", fieldName, " < b", fieldName, ";")
} else {
g.P(helper.Indent(8), "if (a", fieldName, " != b", fieldName, ") {")
Expand Down
8 changes: 8 additions & 0 deletions cmd/protoc-gen-cpp-tableau-loader/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"flag"
"fmt"

"github.com/tableauio/loader/internal/options"
"google.golang.org/protobuf/compiler/protogen"
Expand Down Expand Up @@ -31,6 +32,13 @@ const (
)

func main() {
showVersion := flag.Bool("version", false, "print the version and exit")
flag.Parse()
if *showVersion {
fmt.Printf("protoc-gen-cpp-tableau-loader %v\n", version)
return
}
Comment thread
Kybxd marked this conversation as resolved.

var flags flag.FlagSet
namespace = flags.String("namespace", "tableau", "tableau namespace")
messagerSuffix = flags.String("suffix", "Mgr", "tableau messager name suffix")
Expand Down
6 changes: 3 additions & 3 deletions cmd/protoc-gen-go-tableau-loader/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,16 +118,16 @@ func genIndexSorter(gen *protogen.Plugin, g *protogen.GeneratedFile, descriptor
for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel {
for _, index := range levelMessage.Indexes {
indexContainerName := "index" + strcase.ToCamel(index.Name()) + "Map"
if len(index.KeyFields) != 0 {
if len(index.SortedColFields) != 0 {
g.P("// Index(sort): ", index.Index)
g.P("for _, item := range x.", indexContainerName, " {")
g.P(sortPackage.Ident("Slice"), "(item, func(i, j int) bool {")
for i, field := range index.KeyFields {
for i, field := range index.SortedColFields {
fieldName := ""
for _, leveledFd := range field.LeveledFDList {
fieldName += ".Get" + helper.ParseIndexFieldName(gen, leveledFd) + "()"
}
if i == len(index.KeyFields)-1 {
if i == len(index.SortedColFields)-1 {
g.P("return item[i]", fieldName, " < item[j]", fieldName)
} else {
g.P("if item[i]", fieldName, " != item[j]", fieldName, " {")
Expand Down
8 changes: 8 additions & 0 deletions cmd/protoc-gen-go-tableau-loader/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"flag"
"fmt"

"github.com/tableauio/loader/internal/options"
"google.golang.org/protobuf/compiler/protogen"
Expand All @@ -13,6 +14,13 @@ const version = "0.8.0"
var pkg *string

func main() {
showVersion := flag.Bool("version", false, "print the version and exit")
flag.Parse()
if *showVersion {
fmt.Printf("protoc-gen-cpp-tableau-loader %v\n", version)
return
}

var flags flag.FlagSet
pkg = flags.String("pkg", "tableau", "tableau package name")

Expand Down
16 changes: 8 additions & 8 deletions internal/index/descriptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ func (l *LevelMessage) NeedGen() bool {

type LevelIndex struct {
*Index
MD protoreflect.MessageDescriptor
ColFields []*LevelField
KeyFields []*LevelField
MD protoreflect.MessageDescriptor
ColFields []*LevelField
SortedColFields []*LevelField
}

func (l *LevelIndex) Name() string {
Expand Down Expand Up @@ -96,14 +96,14 @@ func parseLevelMessage(md protoreflect.MessageDescriptor) *LevelMessage {
// parseRecursively parses multi-column index related info.
func parseRecursively(index *Index, prefix string, md protoreflect.MessageDescriptor, levelMessage *LevelMessage) {
colFields := parseInSameLevel(index.Cols, prefix, md, nil)
keyFields := parseInSameLevel(index.Keys, prefix, md, nil)
sortedColFields := parseInSameLevel(index.SortedCols, prefix, md, nil)
if len(colFields) != 0 {
// index belongs to current level
levelMessage.Indexes = append(levelMessage.Indexes, &LevelIndex{
Index: index,
MD: md,
ColFields: colFields,
KeyFields: keyFields,
Index: index,
MD: md,
ColFields: colFields,
SortedColFields: sortedColFields,
})
} else if levelMessage != nil && levelMessage.NextLevel != nil {
// index invalid or belongs to deeper level
Expand Down
16 changes: 8 additions & 8 deletions internal/index/descriptor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func Test_ParseIndexDescriptor(t *testing.T) {
{
Index: &Index{
Cols: []string{"Param"},
Keys: []string{"ID"},
SortedCols: []string{"ID"},
Name: "ItemInfo",
},
MD: md[*protoconf.ItemConf_Item](),
Expand All @@ -67,7 +67,7 @@ func Test_ParseIndexDescriptor(t *testing.T) {
},
},
},
KeyFields: []*LevelField{
SortedColFields: []*LevelField{
{
FD: fd[*protoconf.ItemConf_Item]("id"),
LeveledFDList: []protoreflect.FieldDescriptor{
Expand Down Expand Up @@ -109,7 +109,7 @@ func Test_ParseIndexDescriptor(t *testing.T) {
{
Index: &Index{
Cols: []string{"ID", "Name"},
Keys: []string{"Type", "UseEffectType"},
SortedCols: []string{"Type", "UseEffectType"},
Name: "AwardItem",
},
MD: md[*protoconf.ItemConf_Item](),
Expand All @@ -127,7 +127,7 @@ func Test_ParseIndexDescriptor(t *testing.T) {
},
},
},
KeyFields: []*LevelField{
SortedColFields: []*LevelField{
{
FD: fd[*protoconf.ItemConf_Item]("type"),
LeveledFDList: []protoreflect.FieldDescriptor{
Expand Down Expand Up @@ -327,7 +327,7 @@ func Test_ParseIndexDescriptor(t *testing.T) {
{
Index: &Index{
Cols: []string{"ChapterName"},
Keys: []string{"AwardID"},
SortedCols: []string{"AwardID"},
Name: "NamedChapter",
},
MD: md[*protoconf.ActivityConf_Activity_Chapter](),
Expand All @@ -339,7 +339,7 @@ func Test_ParseIndexDescriptor(t *testing.T) {
},
},
},
KeyFields: []*LevelField{
SortedColFields: []*LevelField{
{
FD: fd[*protoconf.ActivityConf_Activity_Chapter]("award_id"),
LeveledFDList: []protoreflect.FieldDescriptor{
Expand Down Expand Up @@ -391,7 +391,7 @@ func Test_ParseIndexDescriptor(t *testing.T) {
{
Index: &Index{
Cols: []string{"ActivityID"},
Keys: []string{"Goal", "ID"},
SortedCols: []string{"Goal", "ID"},
Name: "",
},
MD: md[*protoconf.TaskConf_Task](),
Expand All @@ -403,7 +403,7 @@ func Test_ParseIndexDescriptor(t *testing.T) {
},
},
},
KeyFields: []*LevelField{
SortedColFields: []*LevelField{
{
FD: fd[*protoconf.TaskConf_Task]("goal"),
LeveledFDList: []protoreflect.FieldDescriptor{
Expand Down
60 changes: 40 additions & 20 deletions internal/index/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,43 @@ func init() {
// Single-column index:
// - ID
// - ID@Item
// - ID<Key>@Item
// - ID<Key, Key2>@Item
// - ID<SortedCol>@Item
// - ID<SortedCol1, SortedCol2>@Item
//
// Multi-column index (composite index):
// - (ID, Name)
// - (ID, Name)@Item
// - (ID, Name)<Key>@Item
// - (ID, Name)<Key1, Key2>@Item
indexRegexp = regexp.MustCompile(`^(?P<cols>\([^)]+\)|[^<@]+)?(<(?P<keys>[^>]+)>)?(@(?P<name>.+))?$`)
// - (ID, Name)<SortedCol>@Item
// - (ID, Name)<SortedCol1, SortedCol2>@Item
indexRegexp = regexp.MustCompile(`^(?P<Cols>\([^)]+\)|[^<@]+)?(<(?P<SortedCols>[^>]+)>)?(@(?P<Name>.+))?$`)
}

// matchIndex parses the index syntax and returns the columns, sorted columns and name.
func matchIndex(text string) (cols, sortedCols, name string) {
match := indexRegexp.FindStringSubmatch(text)
if match == nil {
return "", "", ""
}
for i, expName := range indexRegexp.SubexpNames() {
value := strings.TrimSpace(match[i])
switch expName {
case "Cols":
cols = value
case "SortedCols":
sortedCols = value
case "Name":
name = value
default:
continue
}
}
return cols, sortedCols, name
}

type Index struct {
Cols []string // column names in CamelCase (single-column or multi-column)
Name string // index name in CamelCase
Keys []string // key names in CamelCase (single-column or multi-column)
Cols []string // column names in CamelCase (single-column or multi-column)
Name string // index name in CamelCase
SortedCols []string // sorted column names in CamelCase (single-column or multi-column)
}

func (index *Index) String() string {
Expand All @@ -44,8 +66,8 @@ func (index *Index) String() string {
if len(index.Cols) > 1 {
syntax = "(" + syntax + ")"
}
if len(index.Keys) != 0 {
syntax += "<" + strings.Join(index.Keys, ",") + ">"
if len(index.SortedCols) != 0 {
syntax += "<" + strings.Join(index.SortedCols, ",") + ">"
}
if index.Name != "" {
syntax += "@" + index.Name
Expand All @@ -61,10 +83,10 @@ func ParseWSOptionIndex(md protoreflect.MessageDescriptor) []*Index {
}

func parseIndex(indexStr string) *Index {
cols, sortedCols, name := matchIndex(indexStr)
index := &Index{}
matches := indexRegexp.FindStringSubmatch(indexStr)
// Extract columns
if cols := matches[indexRegexp.SubexpIndex("cols")]; cols != "" {
if cols != "" {
if strings.HasPrefix(cols, "(") && strings.HasSuffix(cols, ")") {
// Multi-column index
cols = cols[1 : len(cols)-1]
Expand Down Expand Up @@ -92,17 +114,15 @@ func parseIndex(indexStr string) *Index {
if len(index.Cols) == 0 {
return nil
}
// Extract keys
if keys := matches[indexRegexp.SubexpIndex("keys")]; keys != "" {
index.Keys = strings.Split(keys, ",")
for i, key := range index.Keys {
index.Keys[i] = strings.TrimSpace(key)
// Extract sortedCols
if sortedCols != "" {
index.SortedCols = strings.Split(sortedCols, ",")
for i, col := range index.SortedCols {
index.SortedCols[i] = strings.TrimSpace(col)
}
}
// Extract name
if name := matches[indexRegexp.SubexpIndex("name")]; name != "" {
index.Name = name
}
index.Name = name
return index
}

Expand Down
32 changes: 16 additions & 16 deletions internal/index/index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,20 @@ func Test_parseIndex(t *testing.T) {
want *Index
}{
{
name: "Single column with single key and name",
input: "Column1<Key1>@IndexName",
name: "Single column with single sorted column and name",
input: "Column1<SortedCol1>@IndexName",
want: &Index{
Cols: []string{"Column1"},
Keys: []string{"Key1"},
SortedCols: []string{"SortedCol1"},
Name: "IndexName",
},
},
{
name: "Multi-column with multi-key and name",
input: "( Column1 , Column2 )< Key1 , Key2 >@IndexName",
name: "Multi-column with multi sorted column and name",
input: "( Column1 , Column2 )< SortedCol1 , SortedCol2 >@IndexName",
want: &Index{
Cols: []string{"Column1", "Column2"},
Keys: []string{"Key1", "Key2"},
SortedCols: []string{"SortedCol1", "SortedCol2"},
Name: "IndexName",
},
},
Expand All @@ -38,50 +38,50 @@ func Test_parseIndex(t *testing.T) {
},
},
{
name: "Multi-column without keys or name",
name: "Multi-column without sorted columns or name",
input: "(Column4, Column5)",
want: &Index{
Cols: []string{"Column4", "Column5"},
},
},
{
name: "Single column with single key only",
input: "Column6<Key6>",
name: "Single column with single sorted column only",
input: "Column6<SortedCol>",
want: &Index{
Cols: []string{"Column6"},
Keys: []string{"Key6"},
SortedCols: []string{"SortedCol"},
},
},
{
name: "zinotest",
input: "ActivityID<Goal,ID>",
want: &Index{
Cols: []string{"ActivityID"},
Keys: []string{"Goal", "ID"},
SortedCols: []string{"Goal", "ID"},
},
},
{
name: "Multi-column with spaces around commas",
input: "(Column7, Column8, Column9)<Key7, Key8, Key9>@IndexName",
input: "(Column7, Column8, Column9)<SortedCol7, SortedCol8, SortedCol9>@IndexName",
want: &Index{
Cols: []string{"Column7", "Column8", "Column9"},
Keys: []string{"Key7", "Key8", "Key9"},
SortedCols: []string{"SortedCol7", "SortedCol8", "SortedCol9"},
Name: "IndexName",
},
},
{
name: "Invalid format (multi-column without parentheses)",
input: "Column10, Column11<Key10, Key11>@IndexName",
input: "Column10, Column11<SortedCol10, SortedCol11>@IndexName",
want: nil,
},
{
name: "Invalid format (single column with parentheses)",
input: "(Column12)<Key12>@IndexName",
input: "(Column12)<SortedCol12>@IndexName",
want: nil,
},
{
name: "Invalid format (empty columns)",
input: "<Key13>@IndexName",
input: "<SortedCol13>@IndexName",
want: nil,
},
}
Expand Down