shad-go/excelwriter
2024-06-05 20:36:34 +03:00
..
README.md Updated to the most recent version, which uses go 1.22 2024-06-05 20:36:34 +03:00
writer.go Updated to the most recent version, which uses go 1.22 2024-06-05 20:36:34 +03:00
writer_test.go Updated to the most recent version, which uses go 1.22 2024-06-05 20:36:34 +03:00

excelwriter [reflect]

В этой задаче нужно обернуть библиотеку для работы с exel'ем в reflect, реализовав интерфейс для построчной записи go объектов в excel

type Writer interface {
	WriteRow(r any) error
}

r — это либо структура, либо map[smth]any, либо указатель на что-то из этого.

smth — это либо строка, либо тип реализующий TextMarshaler

Как должны сериализовываться поля структур подробно написано в интерфейсе. Всё, что не специфицировано в доке и не проверяется тестами можно делать как сочтёте разумным.

Также нужно реализовать конструктор

func New(f *excelize.File) Writer {
	panic("implement me")
}

принимающий на вход инициализированный excel клиент. Можно считать, что excel файл изначально пустой у которого создана 1 страница. Все записи нужно делать в ней.

Пример использования

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'ем определяет наборы популярных стилей в виде enum'а 15 d-mmm-yy. Это число 15 и нужно поддержать в тэге xslx:"date,numfmt:15".

Вопросы со звёздочкой

  1. Как бы вы поддержали в тэгах стили форматирования ячеек (excelize.Fill, excelize.Border ...)?
  2. Как бы вы поддержали в тэгах кастомные стили форматирования числовых значений, те, что не входят в стандартный набор, например 0,"K"?
  3. Как мог бы выглядеть Reader, совместимый с Writer'ом, читающий строчки из excel в Go структуры и map'ы?