68 lines
4 KiB
Markdown
68 lines
4 KiB
Markdown
|
# excelwriter [reflect]
|
|||
|
|
|||
|
В этой задаче нужно обернуть библиотеку для работы с exel'ем в reflect, реализовав интерфейс для построчной записи go объектов в excel
|
|||
|
```go
|
|||
|
type Writer interface {
|
|||
|
WriteRow(r any) error
|
|||
|
}
|
|||
|
```
|
|||
|
r — это либо структура, либо map[smth]any, либо указатель на что-то из этого.
|
|||
|
|
|||
|
smth — это либо строка, либо тип реализующий [TextMarshaler](https://pkg.go.dev/encoding#TextMarshaler)
|
|||
|
|
|||
|
Как должны сериализовываться поля структур подробно написано в интерфейсе.
|
|||
|
Всё, что не специфицировано в доке и не проверяется тестами можно делать как сочтёте разумным.
|
|||
|
|
|||
|
Также нужно реализовать конструктор
|
|||
|
```go
|
|||
|
func New(f *excelize.File) Writer {
|
|||
|
panic("implement me")
|
|||
|
}
|
|||
|
```
|
|||
|
принимающий на вход инициализированный excel клиент.
|
|||
|
Можно считать, что excel файл изначально пустой у которого создана 1 страница. Все записи нужно делать в ней.
|
|||
|
|
|||
|
Пример использования
|
|||
|
```go
|
|||
|
type Movie struct {
|
|||
|
Title string
|
|||
|
Year int `xlsx:"release_year"`
|
|||
|
}
|
|||
|
|
|||
|
func StoreMovies() {
|
|||
|
f := excelize.NewFile()
|
|||
|
_, _ = f.NewSheet("Sheet1")
|
|||
|
|
|||
|
w := excelwriter.New(f)
|
|||
|
_ = w.WriteRow(&Movie{Title: "Blade Runner", Year: 1982})
|
|||
|
_ = w.WriteRow(&Movie{Title: "Blade Runner 2049", Year: 2017})
|
|||
|
_ = w.WriteRow(map[string]any{"title": "Into the wild", "release_year": 2007})
|
|||
|
|
|||
|
out, _ := os.Create("/tmp/movie.xlsx")
|
|||
|
_, _ = f.WriteTo(out)
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
В результате будет создан excel документ со следующим содержимым
|
|||
|
```
|
|||
|
title release_year
|
|||
|
Blade Runner 1982
|
|||
|
Blade Runner 2049 2017
|
|||
|
Into the wild 2007
|
|||
|
```
|
|||
|
|
|||
|
В первой строке хранятся имена колонок, которые вычисляются из имён полей, тэгов и ключей map'ов.
|
|||
|
|
|||
|
Разные структуры могут превращаться в разные наборы колонок.
|
|||
|
Для каждого уникального имени должна быть ровно одна колонка, их нужно "создавать" по мере возникновения.
|
|||
|
|
|||
|
Новые ключи каждого конкретного мапа добавляются в колонки в отсортированном порядке, чтобы при перезапусках на одних и тех же данных получались одинаковые excel'ки.
|
|||
|
|
|||
|
Помимо имён полей в xlsx тэгах для числовых полей нужно поддержать стили форматирования.
|
|||
|
Например, в excel нет отдельного типа для дат. Дата — это 15-и значный double (excel тип Number) со стилем форматирования `d-mmm-yy`. Библиотека для работы с excel'ем определяет [наборы популярных стилей](https://pkg.go.dev/github.com/xuri/excelize/v2#File.NewStyle) в виде enum'а `15 d-mmm-yy`. Это число 15 и нужно поддержать в тэге `xslx:"date,numfmt:15"`.
|
|||
|
|
|||
|
## Вопросы со звёздочкой
|
|||
|
1. Как бы вы поддержали в тэгах стили форматирования ячеек (excelize.Fill, excelize.Border ...)?
|
|||
|
2. Как бы вы поддержали в тэгах кастомные стили форматирования числовых значений, те, что не входят в стандартный набор, например `0,"K"`?
|
|||
|
3. Как мог бы выглядеть Reader, совместимый с Writer'ом, читающий строчки из excel в Go структуры и map'ы?
|