aboutsummaryrefslogblamecommitdiffstats
path: root/cmd/dbasik-api/return.go
blob: 33209800791290f096f51dd52729498c8f323087 (plain) (tree)
1
2
3
4
5
6
7
8
9


            
                     




                                   











                                   










                                



                            








































                                                                                          














































                                                                                                       







                                                
 






















                                                      
                                                             






                                                       
                                                       











                                                 
                                                                                                             
                                                                     
                                                                    
 
 
                                                                                                
                                                         
                                                              
 
package main

import (
	"archive/zip"
	"fmt"
	"github.com/tealeg/xlsx/v3"
	"path/filepath"
)

type FilePreparer interface {
	Prepare() ([]string, error)
}

type FileSource struct {
	FilePath string
}

type DirectoryFilePackage struct {
	FileSource
}

type ReturnLine struct {
	Sheet   string
	CellRef string
	Value   string
}

type Return struct {
	Name        string
	ReturnLines []ReturnLine
}

type ZipFilePackage struct {
	FileSource
}

// NewReturnLine creates a new ReturnLine object
func NewReturnLine(sheet, cellRef, value string) (*ReturnLine, error) {
	if err := validateInputs(sheet, cellRef, value); err != nil {
		return nil, err
	}

	if !validateSpreadsheetCell(cellRef) {
		return nil, fmt.Errorf("cellRef must be A1 format")
	}

	return &ReturnLine{
		Sheet:   sheet,
		CellRef: cellRef,
		Value:   value,
	}, nil
}

func validateInputs(sheet, cellRef, value string) error {
	if sheet == "" {
		return fmt.Errorf("sheet parameter is required")
	}
	if cellRef == "" {
		return fmt.Errorf("cellRef parameter is required")
	}
	if value == "" {
		return fmt.Errorf("value parameter is required")
	}
	return nil
}

func NewReturn(name string, dm *Datamap, returnLines []ReturnLine) (*Return, error) {
	if len(returnLines) == 0 {
		return nil, fmt.Errorf("ReturnLines must contain at least one ReturnLine")
	}

	return &Return{
		Name:        name,
		ReturnLines: returnLines,
	}, nil
}

func ParseXLSX(filePath string, dm *Datamap) (*Return, error) {
	// Use tealeg/xlsx to parse the Excel file
	wb, err := xlsx.OpenFile(filePath)
	if err != nil {
		return nil, err
	}

	// Get the set of sheets from the Datamap
	sheets := GetSheetsFromDM(*dm)

	// Loop through all DatamapLines
	returnLines := []ReturnLine{}
	for _, dml := range dm.DMLs {
		// Check if the sheet for this DatamapLine is in the set of sheets
		if !contains(sheets, dml.Sheet) {
			continue
		}

		sh, ok := wb.Sheet[dml.Sheet]
		if !ok {
			return nil, fmt.Errorf("sheet %s not found in Excel file", dml.Sheet)
		}

		col, row, err := xlsx.GetCoordsFromCellIDString(dml.CellRef)
		if err != nil {
			return nil, err
		}
		cell, err := sh.Cell(row, col)
		if err != nil {
			return nil, err
		}
		returnLines = append(returnLines, ReturnLine{
			Sheet:   dml.Sheet,
			CellRef: dml.CellRef,
			Value:   cell.Value, // or cell.FormattedValue() if you need formatted values
		})
	}

	// Here we create a new Return object with the name of the Excel file and the ReturnLines slice
	// that we just populated
	rtn, err := NewReturn(filepath.Base(filePath), dm, returnLines)
	if err != nil {
		return nil, err
	}
	return rtn, nil
}

func contains(slice []string, str string) bool {
	for _, s := range slice {
		if s == str {
			return true
		}
	}
	return false
}

func PrepareFiles(fp FilePreparer) ([]string, error) {
	ch := make(chan string, 100)

	go func() {
		defer close(ch)
		files, err := fp.Prepare()
		if err != nil {
			ch <- err.Error()
		}

		for _, f := range files {
			ch <- f
		}
	}()

	var files []string
	for f := range ch {
		files = append(files, f)
	}

	return files, nil
}

func (fp *DirectoryFilePackage) Prepare() ([]string, error) {
	files, err := filepath.Glob(fp.FilePath + "/*")
	if err != nil {
		return nil, err
	}
	return files, nil
}

func (fp *ZipFilePackage) Prepare() ([]string, error) {
	files, err := zip.OpenReader(fp.FilePath)
	if err != nil {
		return nil, err
	}
	defer files.Close()
	out := []string{}
	for _, file := range files.File {
		out = append(out, file.Name)
	}
	return out, nil
}

// NewDirectoryFilePackage creates a new DirectoryFilePackage object with the given filePath to the directory
func NewDirectoryFilePackage(filePath string) *DirectoryFilePackage {
	return &DirectoryFilePackage{FileSource{FilePath: filePath}}
}

// NewZipFilePackage creates a new ZipFilePackage object with the given filePath to the zip file
func NewZipFilePackage(filePath string) *ZipFilePackage {
	return &ZipFilePackage{FileSource{FilePath: filePath}}
}