Metasheet
The metasheet is a worksheet named "@TABLEAU" to specify sheet-level options of tableau parser.
Overview
Options below can be specified in the metasheet @TABLEAU
to affect the corresponding worksheet’s layout, ability, loader and so on.
Option | Type | Description |
---|---|---|
Sheet | string | The worksheet name to be processed. Specially, # refers to the workbook name, so you can set workbook’s Alias . |
Alias | string | For worksheet, alias is used as proto message name. For workbook # , alias is used as proto file name (without file extension). |
Namerow | int32 | Exact row number of column name definition at a worksheet. Default: 1 . |
Typerow | int32 | Exact row number of column type definition at a worksheet. Default: 2 . |
Noterow | int32 | Exact row number of column note definition at a worksheet. Default: 3 . |
Datarow | int32 | Start row number of data at a worksheet. Default: 4 . |
Nameline | int32 | The line number of column name definition in a cell. 0 means the whole cell.Default: 0 . |
Typeline | int32 | The line number of column type definition in a cell. 0 means the whole cell.Default: 0 . |
Transpose | bool | Interchanging the rows and columns of a given sheet. |
Nested | bool | Nested naming of the namerow. Default: false . |
Sep | string | Sheet-level separator. |
Subsep | string | Sheet-level subseparator. |
Merger | []string | Merge multiple sheets (comma-separated) into one with the same structure. Each element can be: - just a workbook file path or glob path (relative to this workbook): <Workbook> , then the sheet name is the same as this sheet.- a workbook file path (relative to this workbook) with a worksheet name: <Workbook>#<Worksheet> . |
AdjacentKey | bool | Merge adjacent rows with the same key. If the key cell is not set, it will be treated the same as the nearest key above the same column. Default: false . |
FieldPresence | bool | In order to track field presence of basic types (numeric, string, bytes, and enums), the generated field will be labeled optional .Default: false . |
Mode | Mode | Sheet mode. Available modes: - MODE_ENUM_TYPE - MODE_ENUM_TYPE_MULTI - MODE_STRUCT_TYPE - MODE_STRUCT_TYPE_MULTI - MODE_UNION_TYPE - MODE_UNION_TYPE_MULTI |
Scatter | []string | Convert multiple sheets separately with same schema. Each element can be: - a workbook name or Glob which is relative to this workbook: <Workbook> , then the sheet name is the same as this sheet.- or a workbook name which is relative to this workbook with a worksheet name: <Workbook>#<Worksheet> . |
Optional | bool | Whether all fields in this sheet are optional (field name existence). |
Patch | Patch | Sheet patch type. - PATCH_REPLACE - PATCH_MERGE |
WithParentDir | bool | confgen: export JSON/Bin/Text files with parent dir created. |
ScatterWithoutBookName | bool | confgen(scatter): export JSON/Bin/Text filenames without book name prefix. |
OrderedMap | bool | Generate OrderedMap accessers or not. |
Index | []string | Generate index accessers. - Single-column Index format: Column<ColumnX,ColumnY,...>@IndexName .- Multi-column Index format: (Column1,Column2,...)<ColumnX,ColumnY,...>@IndexName . |
OrderedIndex | []string | Generate OrderedIndex accessers. - Single-column OrderedIndex format: Column<ColumnX,ColumnY,...>@IndexName .- Multi-column OrderedIndex format: (Column1,Column2,...)<ColumnX,ColumnY,...>@IndexName . |
LangOptions | map<string, string> | Specify loader language options. Valid keys are: OrderedMap , Index .Different kvs must be seperated by , and one key value must be seperated by : .If one key doesn’t exist in map, it means that this loader option is supported in all languages. Valid values are all combinations of cpp , go with space as seperator.Examples: - OrderedMap:cpp,Index:cpp go // ordered map supported in cpp, index supported in cpp and go- OrderedMap:cpp // ordered map supported in cpp, index supported in all languages |
Empty @TABLEAU
If metasheet @TABLEAU
is empty, then all other worksheets in the same workbook will be processed.
A simple example
There is a worksheet Sheet1
in HelloWorld.xlsx, we want to rename sheet to
ItemConf
, define custom seperator as |
, and generate ordered map accessers.
So the metasheet @TABLEAU
in HelloWorld.xlsx should be configured as:
ID | Name |
---|---|
map<uint32, Item> | string |
Item’s ID | Item’s Name |
1 | Apple |
2 | Orange |
3 | Banana |
Sheet | Alias | Sep | OrderedMap |
---|---|---|---|
Sheet1 | ItemConf | | | true |
Workbook Alias
The generated proto file name is the snake case of input file name. For example, if you have a workbook named HelloWorld.xlsx, the generated proto file name is hello_world.proto. If you want to manually specify a name for the generated proto file, you can also use the Alias
option. In this scenario, #
refers to the workbook name.
A worksheet ItemConf
in HelloWorld.xlsx:
ID | Name |
---|---|
map<uint32, Item> | string |
Item’s ID | Item’s Name |
1 | Apple |
2 | Orange |
3 | Banana |
Sheet | Alias |
---|---|
# | custom_conf |
Sheet1 | ItemConf |
Generated:
custom_conf.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
map<uint32, Item> item_map = 1 [(tableau.field) = {key:"ID" layout:LAYOUT_VERTICAL}];
message Item {
uint32 id = 1 [(tableau.field) = {name:"ID"}];
string name = 2 [(tableau.field) = {name:"Name"}];
}
}
Option Mode
Sheet mode defines how tableauc (protogen) parses the sheet: data or types.
Available modes:
MODE_DEFAULT
: Default mode, which defines sheet’s data structure.MODE_ENUM_TYPE
: Define single enum type in a sheet, see Example.MODE_ENUM_TYPE_MULTI
: Define multiple enum types in a sheet, see Example.MODE_STRUCT_TYPE
: Define single struct type in a sheet, see Example.MODE_STRUCT_TYPE_MULTI
: Define multiple struct types in a sheet, see Example.MODE_UNION_TYPE
: Define single union type in a sheet, see Example.MODE_UNION_TYPE_MULTI
: Define multiple union types in a sheet, see Example.
Option Transpose
In linear algebra, transpose of a matrix is an operator which flips a matrix over its diagonal. Likewise, transpose of a sheet (2D matrix) means interchanging its rows into columns or vice versa.
See more details about Excel: Transpose (rotate) data from rows to columns or vice versa.
Option Transpose
is specified as true
in the metasheet @TABLEAU
.
A worksheet HeroConf
in HelloWorld.xlsx:
ID | int32 | Hero’s ID | 123 |
---|---|---|---|
Name | string | Hero’s name | Robin |
Desc | string | Hero’s description | A big hero! |
Skill | []int32 | Hero’s skills | 100,101,102 |
Sheet | Transpose |
---|---|
HeroConf | true |
Generated:
hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message HeroConf {
option (tableau.worksheet) = {name:"HeroConf" transpose:true};
int32 id = 1 [(tableau.field) = {name:"ID"}];
string name = 2 [(tableau.field) = {name:"Name"}];
string desc = 3 [(tableau.field) = {name:"Desc"}];
repeated int32 skill_list = 4 [(tableau.field) = {name:"Skill" layout:LAYOUT_INCELL}];
}
HeroConf.json
{
"id": 123,
"name": "Robin",
"desc": "A big hero!",
"skillList": [
100,
101,
102
]
}
Option Merger
Option Merger
is used to merge multiple sheets (comma-separated) with same schema to one.
Each element can be:
- just a workbook file path or Glob path (relative to this workbook):
<Workbook>
, then the sheet name is the same as this sheet. - a workbook file path (relative to this workbook) with a worksheet name:
<Workbook>#<Worksheet>
.
For example:
The first (main) workbook: a worksheet ZoneConf
in MergerMain.xlsx (with @TABLEAU
):
ID | Name | Difficulty |
---|---|---|
map<uint32, Zone> | string | int32 |
Zoneās ID | Zoneās name | Zoneās difficulty |
1 | Infinity | 100 |
Sheet | Merger |
---|---|
ZoneConf | Merger*.xlsx |
The second (sub) workbook: a worksheet ZoneConf
in Merger2.xlsx (without @TABLEAU
):
ID | Name | Difficulty |
---|---|---|
map<uint32, Zone> | string | int32 |
Zoneās ID | Zoneās name | Zoneās difficulty |
2 | Desert | 200 |
The third (sub) workbook: a worksheet ZoneConf
in Merger3.xlsx (without @TABLEAU
):
ID | Name | Difficulty |
---|---|---|
map<uint32, Zone> | string | int32 |
Zoneās ID | Zoneās name | Zoneās difficulty |
3 | Snowfield | 300 |
Generated:
merger_main.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ZoneConf {
option (tableau.worksheet) = {name:"ZoneConf" merger:"Merger*.xlsx"};
map<uint32, Zone> zone_map = 1 [(tableau.field) = {key:"ID" layout:LAYOUT_VERTICAL}];
message Zone {
uint32 id = 1 [(tableau.field) = {name:"ID"}];
string name = 2 [(tableau.field) = {name:"Name"}];
int32 difficulty = 3 [(tableau.field) = {name:"Difficulty"}];
}
}
HeroConf.json
{
"zoneMap": {
"1": {
"id": 1,
"name": "Infinity",
"difficulty": 100
},
"2": {
"id": 2,
"name": "Desert",
"difficulty": 200
},
"3": {
"id": 3,
"name": "Snowfield",
"difficulty": 300
}
}
}
Option Scatter
Option Scatter
is used to scatter multiple sheets (comma-separated) with same schema to different generated config files.
Each element can be:
- just a workbook file path or Glob path (relative to this workbook):
<Workbook>
, then the sheet name is the same as this sheet. - a workbook file path (relative to this workbook) with a worksheet name:
<Workbook>#<Worksheet>
.
For example, there are three workbooks (each with same sheet schema, and Scatter1.xlsx is the main workbook):
- Scatter1.xlsx
- Scatter2.xlsx
- Scatter3.xlsx
The first (main) workbook: a worksheet ZoneConf
in Scatter1.xlsx (with @TABLEAU
):
ID | Name | Difficulty |
---|---|---|
map<uint32, Zone> | string | int32 |
Zoneās ID | Zoneās name | Zoneās difficulty |
1 | Infinity | 100 |
Sheet | Scatter |
---|---|
ZoneConf | Scatter*.xlsx |
The second (sub) workbook: a worksheet ZoneConf
in Scatter2.xlsx (without @TABLEAU
):
ID | Name | Difficulty |
---|---|---|
map<uint32, Zone> | string | int32 |
Zoneās ID | Zoneās name | Zoneās difficulty |
2 | Desert | 200 |
The third (sub) workbook: a worksheet ZoneConf
in Scatter3.xlsx (without @TABLEAU
):
ID | Name | Difficulty |
---|---|---|
map<uint32, Zone> | string | int32 |
Zoneās ID | Zoneās name | Zoneās difficulty |
3 | Snowfield | 300 |
Generated protoconf:
scatter_1.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ZoneConf {
option (tableau.worksheet) = {name:"ZoneConf" scatter:"Scatter*.xlsx"};
map<uint32, Zone> zone_map = 1 [(tableau.field) = {key:"ID" layout:LAYOUT_VERTICAL}];
message Zone {
uint32 id = 1 [(tableau.field) = {name:"ID"}];
string name = 2 [(tableau.field) = {name:"Name"}];
int32 difficulty = 3 [(tableau.field) = {name:"Difficulty"}];
}
}
It is supposed to generate three different config files (name pattern: <BookName>_<SheetName>
):
Scatter1_ZoneConf.json
{
"zoneMap": {
"1": {
"id": 1,
"name": "Infinity",
"difficulty": 100
}
}
}
Scatter2_ZoneConf.json
{
"zoneMap": {
"2": {
"id": 2,
"name": "Desert",
"difficulty": 200
}
}
}
Scatter3_ZoneConf.json
{
"zoneMap": {
"3": {
"id": 3,
"name": "Snowfield",
"difficulty": 300
}
}
}
Option OrderedMap
š¢ It only applies to each level messageās first map field.
If you set OrderedMap
to true
, then tableau loader plugins will generate ordered map APIs:
Option Index
Option Index
can be specified to generate index accessers.
There are two kinds of indexes:
- Single-column Index
- Multi-column Index (aka Composite Index).
If you set Index
appropriately, then tableau loader plugins will generate index APIs:
Each column type can be:
- scalar: numbers, booleans, strings, and bytes.
- enum: e.g.:
enum<.FruiteType>
- incell scalar list: e.g:
[]int32
- incell enum list: e.g:
[]enum<.FruiteType>
Example: two worksheets ItemConf and ShopConf in HelloWorld.xlsx:
- ItemConf: index on columns of the same struct as map value.
- ShopConf: index on columns of the same struct as list element.
ID | Name | Desc |
---|---|---|
map<int32, Item> | string | string |
Item’s ID | Item’s name | Item’s desc |
1 | Apple | A kind of delicious fruit. |
2 | Orange | A kind of sour fruit. |
3 | Banana | A kind of calorie-rich fruit. |
ID | Type | Desc |
---|---|---|
[Shop]int32 | int32 | string |
Shop’s ID | Shop’s type | Shop’s desc |
1 | 1 | Shoes shop. |
2 | 1 | T-Shirt shop. |
3 | 2 | Fruite shop. |
Sheet | Index | |
---|---|---|
ItemConf | ID@Item, Name@AwardItem, (ID,Name)@SpecialItem | |
ShopConf | ID@Shop, Type@ThemeShop, (ID,Type)@SpecialShop |
Single-column Index
Format: Column<ColumnX,ColumnY,...>@IndexName
.
The sign @
is the separator between column name and index name. if
IndexName
is not set, it will be this columnās parent struct type name.
One or more indexes can be specified by comma-separated rule. The columns in
the angle brackets <>
specify the sorting columns, which the result array
of same index key sort by.
Examples:
ID
ID@Item
ID<ID>@Item
: result array by ID.ID<Type,Priority>@Item
: result array by Type and Priority.ID, Name@AwardItem
ID@Item, Name@AwardItem
Multi-column Index
Format: (Column1,Column2,...)<ColumnX,ColumnY,...>@IndexName
.
Multi-column Index (aka Composite Index) is composed of multiple columns in the same struct (in list or map) to increase query speed.
The sign @
is the separator between enclosed column names by parentheses and
index name. If IndexName
is not set, it will be this columnās parent struct
type name. One or more indexes can be specified by comma-separated rule. The
columns in the angle brackets <>
specify the sorting columns, which the
result array of same index key sort by.
Examples:
(ID,Name)
: index name not set, then determined by parent struct type name.(ID,Name)@AwardItem
(ID,Name)<ID>
: result array by ID.(ID,Type)<Type,Priority>@Item
: result array by Type and Priority.ID@Item, (ID,Name)@AwardItem
: one single-column index and one multi-column index.
Option OrderedIndex
Option OrderedIndex
can be specified to generate ordered index accessers.
There are two kinds of ordered indexes:
- Single-column OrderedIndex
- Multi-column OrderedIndex (aka Composite OrderedIndex).
If you set OrderedIndex
appropriately, then tableau loader plugins will generate index APIs:
Single-column OrderedIndex
Format: Column<ColumnX,ColumnY,...>@IndexName
.
The sign @
is the separator between column name and index name. if
IndexName
is not set, it will be this columnās parent struct type name.
One or more indexes can be specified by comma-separated rule. The columns in
the angle brackets <>
specify the sorting columns, which the result array
of same index key sort by.
Examples:
ID
ID@Item
ID<ID>@Item
: sort result array by ID.ID<Type,Priority>@Item
: sort result array by Type and Priority.ID, Name@AwardItem
ID@Item, Name@AwardItem
Multi-column OrderedIndex
ā ļø Not supported yet.
Option Patch
// Patch type for both sheet-level and field-level.
enum Patch {
PATCH_NONE = 0;
// 1 Sheet-level patch option "PATCH_REPLACE"
// - replace whole message
// 2 Top-field patch option "PATCH_REPLACE"
// - list: Clear field firstly, and then all elements of this list field
// in src are appended to the corresponded list fields in dst.
// - map: Clear field firstly, and then all entries of this map field in src
// are copied into the corresponding map field in dst.
PATCH_REPLACE = 1;
// Merge src into dst, which must be a message with the same descriptor.
// - scalar: Populated scalar fields in src are copied to dst.
// - message: Populated singular messages in src are merged into dst by
// recursively calling [proto.Merge](https://pkg.go.dev/google.golang.org/protobuf/proto#Merge).
// - list: The elements of every list field in src are appended to the
// corresponded list fields in dst.
// - map: The entries of every map field in src are copied into the
// corresponding map field in dst, possibly replacing existing entries.
// - unknown: The unknown fields of src are appended to the unknown
// fields of dst.
PATCH_MERGE = 2;
}
Option Sep
Sheet-level separator for separating:
- incell list elements (scalar or struct).
- incell map items.
If not set, it will use global-level seq (default: ,
) in tableauc yaml.config.
Option Subsep
Sheet-level subseparator for separating:
- key-value pair of each incell map item.
- struct fields of each incell struct list element.
If not set, it will use global-level subseq (default: :
) in tableauc yaml.config.