Skip to main content

Tabular

The tabular package is the foundation for structured data import/export in VEF. It provides a tag-driven schema system and common interfaces that are implemented by the Excel and CSV packages.

Architecture

tabular (core)
├── Schema — tag parsing, column metadata
├── Importer — import interface
├── Exporter — export interface
├── Formatter — export value formatting
└── ValueParser — import value parsing

excel (implementation) csv (implementation)
├── excel.NewImporterFor[T]() ├── csv.NewImporterFor[T]()
└── excel.NewExporterFor[T]() └── csv.NewExporterFor[T]()

tabular Tag

Use struct tags to define how fields map to columns in Excel/CSV files:

type Employee struct {
orm.FullAuditedModel `tabular:"-"`

Name string `tabular:"姓名,width:20"`
Email string `tabular:"邮箱,width:30"`
Department string `tabular:"name:部门,order:2,width:15"`
JoinDate timex.Date `tabular:"入职日期,format:2006-01-02,width:15"`
Salary decimal.Decimal `tabular:"薪资,width:12,format:#,##0.00"`
Status string `tabular:"状态,default:active,formatter:status"`
}

Tag Attributes

AttributeTypeDescription
(default value)stringColumn header name
namestringExplicit column name (alternative to default)
orderintColumn display order (0-based, default: field declaration order)
widthfloat64Column width hint (used by Excel export)
defaultstringDefault value for empty cells during import
formatstringFormat template (date format, number format)
formatterstringCustom formatter name for export
parserstringCustom parser name for import

Special Tags

TagMeaning
tabular:"-"Ignore this field completely
tabular:"dive"Recurse into embedded struct fields

Schema

The Schema type pre-parses tabular metadata from struct fields at initialization time:

schema := tabular.NewSchemaFor[Employee]()

columns := schema.Columns() // []*Column — all parsed columns
names := schema.ColumnNames() // []string{"姓名", "邮箱", ...}
count := schema.ColumnCount() // 6

Columns are automatically sorted by order attribute. Fields without an explicit order use their declaration order.

Interfaces

Importer

type Importer interface {
RegisterParser(name string, parser ValueParser)
ImportFromFile(filename string) (any, []ImportError, error)
Import(reader io.Reader) (any, []ImportError, error)
}

Exporter

type Exporter interface {
RegisterFormatter(name string, formatter Formatter)
ExportToFile(data any, filename string) error
Export(data any) (*bytes.Buffer, error)
}

Formatter (Export)

type Formatter interface {
Format(value any) (string, error)
}

// Convenience adapter
tabular.FormatterFunc(func(value any) (string, error) { ... })

ValueParser (Import)

type ValueParser interface {
Parse(cellValue string, targetType reflect.Type) (any, error)
}

// Convenience adapter
tabular.ValueParserFunc(func(cellValue string, targetType reflect.Type) (any, error) { ... })

Default Type Support

The built-in DefaultParser and DefaultFormatter handle these types automatically:

Go TypeImport (Parse)Export (Format)
stringDirect assignmentDirect output
int, int8int64Integer parsingInteger formatting
uint, uint8uint64Unsigned int parsingInteger formatting
float32, float64Float parsingFloat formatting
booltrue/false, 1/0Bool formatting
decimal.DecimalDecimal string parsingDecimal formatting
timex.Date / timex.DateTimeUses format attributeUses format attribute
*T (pointer types)Nil for empty, parsed otherwiseHandles nil gracefully

Error Types

ImportError

type ImportError struct {
Row int // 1-based row number (including header)
Column string // Column header name
Field string // Struct field name
Err error // Underlying error
}

Import errors are returned per-row without stopping the import process. This allows batch processing where valid rows are imported and invalid rows are reported.

ExportError

type ExportError struct {
Row int // 0-based data row index
Column string // Column header name
Field string // Struct field name
Err error // Underlying error
}

Implementations

PackageFormatDocumentation
excel.xlsx (Excel)Excel Documentation
csv.csv (CSV/TSV)CSV Documentation

CRUD Integration

The Export and Import CRUD builders use tabular internally:

// Export builder
crud.NewExport[Employee, EmployeeSearch]().
WithDefaultFormat("excel")

// Import builder
crud.NewImport[Employee]().
WithDefaultFormat("excel").
WithPreImport(func(ctx context.Context, models []Employee) error {
// Validate or transform before insert
return nil
})