0
\$\begingroup\$

The code below works as intended: write data by iterating over columns, while iterating over rows while iterating over sheets.

func createXlSXFile(sheets []Sheet) (*bytes.Buffer, error) {
    file := excelize.NewFile()
    file.SetSheetName("Sheet1", sheets[0].Title)
    defer func() {
            if err := file.Close(); err != nil {
                    fmt.Println(err)
            }
    }()

    for i := range sheets {
            if 0 != i {
                    s, _ := file.NewSheet(sheets[i].Title)
                    file.SetActiveSheet(s)
            }
            for j := range sheets[i].Columns {
                    cellName, _ := excelize.CoordinatesToCellName(j+1, 1)
                    file.SetCellValue(
                            sheets[i].Title,
                            cellName,
                            sheets[i].Columns[j].Title,
                    )
            }

            for j := range sheets[i].Dataset {
                    for k := range sheets[i].Columns {
                            cellName, _ := excelize.CoordinatesToCellName(k+1, j+2)
                            file.SetCellValue(
                                    sheets[i].Title,
                                    cellName,
                                    sheets[i].Columns[k].Getter(*(sheets[i].Dataset[j])),
                            )
                    }
            }
    }

    return file.WriteToBuffer()
}

In order for the function above to be independent of any input-type, the Sheet type is defined as follows:

type Sheet struct {
    Title   string
    Columns []Column
    Dataset []*any
}
type Column struct {
    Title  string
    Getter func(any) string
}

Example of usage:

sheets := []Sheet{
    {
        Title:   "Production Tenants",
        Dataset: prodTenants,
        Columns: []Column{
            {
                Title: "Tenant Name",
                Getter: func(t any) string {
                    tnnt, ok := t.(Tenant)
                    if !ok {
                        return "TYPE ASSERTION FAILED"
                    }
                    return tnnt.Name()
                },
            },
        },
    },
    {
        Title: "Production Accounts",
        Dataset: prodAccounts,
        Columns: []Column{
            {
                Title: "Account ID",
                Getter: func(t any) string {
                    acc, ok := t.(Account)
                    if !ok {
                        return "TYPE ASSERTION FAILED"
                    }
                    return acc.ID()
                },
            },
        },
    },
}

result, _ := createXlSXFile(sheets)

The issue with this implementation is:

  1. For every Sheet, in order to create the a dataset, I need to iterate over the actual data-variables and wrap them into interface-variables.
  2. For every Getter function, I need to assert a type.

Another possible implementation I can explore is to create a type-dependent create-sheet function and then append the sheets into a single document.

Is there a better way or a more GO-idiomatic way to implement the above functionality?

\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.