This makes 6 functions concurrency safety

- These 6 functions now support concurrency safe: SetColWidth, GetColWidth, SetColVisible, GetColVisible, SetColStyle and GetColStyle
This commit is contained in:
xuri 2022-09-11 00:04:04 +08:00
parent c72fb747b8
commit b6cc43d824
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7
8 changed files with 79 additions and 32 deletions

15
cell.go
View File

@ -60,7 +60,7 @@ var cellTypes = map[string]CellType{
// worksheet name and axis in spreadsheet file. If it is possible to apply a
// format to the cell value, it will do so, if not then an error will be
// returned, along with the raw value of the cell. All cells' values will be
// the same in a merged range.
// the same in a merged range. This function is concurrency safe.
func (f *File) GetCellValue(sheet, axis string, opts ...Options) (string, error) {
return f.getCellStringFunc(sheet, axis, func(x *xlsxWorksheet, c *xlsxC) (string, bool, error) {
val, err := c.getValueFrom(f, f.sharedStringsReader(), parseOptions(opts...).RawCellValue)
@ -85,10 +85,10 @@ func (f *File) GetCellType(sheet, axis string) (CellType, error) {
return cellType, err
}
// SetCellValue provides a function to set the value of a cell. The specified
// coordinates should not be in the first row of the table, a complex number
// can be set with string text. The following shows the supported data
// types:
// SetCellValue provides a function to set the value of a cell. This function
// is concurrency safe. The specified coordinates should not be in the first
// row of the table, a complex number can be set with string text. The
// following shows the supported data types:
//
// int
// int8
@ -1047,8 +1047,9 @@ func (f *File) SetCellRichText(sheet, cell string, runs []RichTextRun) error {
}
// SetSheetRow writes an array to row by given worksheet name, starting
// coordinate and a pointer to array type 'slice'. For example, writes an
// array to row 6 start with the cell B6 on Sheet1:
// coordinate and a pointer to array type 'slice'. This function is
// concurrency safe. For example, writes an array to row 6 start with the cell
// B6 on Sheet1:
//
// err := f.SetSheetRow("Sheet1", "B6", &[]interface{}{"1", nil, 2})
func (f *File) SetSheetRow(sheet, axis string, slice interface{}) error {

View File

@ -64,7 +64,24 @@ func TestConcurrency(t *testing.T) {
_, err := cols.Rows()
assert.NoError(t, err)
}
// Concurrency set columns style
assert.NoError(t, f.SetColStyle("Sheet1", "C:E", style))
// Concurrency get columns style
styleID, err := f.GetColStyle("Sheet1", "D")
assert.NoError(t, err)
assert.Equal(t, style, styleID)
// Concurrency set columns width
assert.NoError(t, f.SetColWidth("Sheet1", "A", "B", 10))
// Concurrency get columns width
width, err := f.GetColWidth("Sheet1", "A")
assert.NoError(t, err)
assert.Equal(t, 10.0, width)
// Concurrency set columns visible
assert.NoError(t, f.SetColVisible("Sheet1", "A:B", true))
// Concurrency get columns visible
visible, err := f.GetColVisible("Sheet1", "A")
assert.NoError(t, err)
assert.Equal(t, true, visible)
wg.Done()
}(i, t)
}

31
col.go
View File

@ -184,7 +184,8 @@ func columnXMLHandler(colIterator *columnXMLIterator, xmlElement *xml.StartEleme
}
// Cols returns a columns iterator, used for streaming reading data for a
// worksheet with a large data. For example:
// worksheet with a large data. This function is concurrency safe. For
// example:
//
// cols, err := f.Cols("Sheet1")
// if err != nil {
@ -239,8 +240,8 @@ func (f *File) Cols(sheet string) (*Cols, error) {
}
// GetColVisible provides a function to get visible of a single column by given
// worksheet name and column name. For example, get visible state of column D
// in Sheet1:
// worksheet name and column name. This function is concurrency safe. For
// example, get visible state of column D in Sheet1:
//
// visible, err := f.GetColVisible("Sheet1", "D")
func (f *File) GetColVisible(sheet, col string) (bool, error) {
@ -252,6 +253,8 @@ func (f *File) GetColVisible(sheet, col string) (bool, error) {
if err != nil {
return false, err
}
ws.Lock()
defer ws.Unlock()
if ws.Cols == nil {
return true, err
}
@ -266,7 +269,7 @@ func (f *File) GetColVisible(sheet, col string) (bool, error) {
}
// SetColVisible provides a function to set visible columns by given worksheet
// name, columns range and visibility.
// name, columns range and visibility. This function is concurrency safe.
//
// For example hide column D on Sheet1:
//
@ -284,6 +287,8 @@ func (f *File) SetColVisible(sheet, columns string, visible bool) error {
if err != nil {
return err
}
ws.Lock()
defer ws.Unlock()
colData := xlsxCol{
Min: start,
Max: end,
@ -399,9 +404,9 @@ func (f *File) SetColOutlineLevel(sheet, col string, level uint8) error {
}
// SetColStyle provides a function to set style of columns by given worksheet
// name, columns range and style ID. Note that this will overwrite the
// existing styles for the columns, it won't append or merge style with
// existing styles.
// name, columns range and style ID. This function is concurrency safe. Note
// that this will overwrite the existing styles for the columns, it won't
// append or merge style with existing styles.
//
// For example set style of column H on Sheet1:
//
@ -426,6 +431,7 @@ func (f *File) SetColStyle(sheet, columns string, styleID int) error {
if err != nil {
return err
}
ws.Lock()
if ws.Cols == nil {
ws.Cols = &xlsxCols{}
}
@ -444,6 +450,7 @@ func (f *File) SetColStyle(sheet, columns string, styleID int) error {
fc.Width = c.Width
return fc
})
ws.Unlock()
if rows := len(ws.SheetData.Row); rows > 0 {
for col := start; col <= end; col++ {
from, _ := CoordinatesToCellName(col, 1)
@ -455,7 +462,7 @@ func (f *File) SetColStyle(sheet, columns string, styleID int) error {
}
// SetColWidth provides a function to set the width of a single column or
// multiple columns. For example:
// multiple columns. This function is concurrency safe. For example:
//
// f := excelize.NewFile()
// err := f.SetColWidth("Sheet1", "A", "H", 20)
@ -479,6 +486,8 @@ func (f *File) SetColWidth(sheet, startCol, endCol string, width float64) error
if err != nil {
return err
}
ws.Lock()
defer ws.Unlock()
col := xlsxCol{
Min: min,
Max: max,
@ -623,6 +632,8 @@ func (f *File) positionObjectPixels(sheet string, col, row, x1, y1, width, heigh
// sheet name and column number.
func (f *File) getColWidth(sheet string, col int) int {
ws, _ := f.workSheetReader(sheet)
ws.Lock()
defer ws.Unlock()
if ws.Cols != nil {
var width float64
for _, v := range ws.Cols.Col {
@ -639,7 +650,7 @@ func (f *File) getColWidth(sheet string, col int) int {
}
// GetColStyle provides a function to get column style ID by given worksheet
// name and column name.
// name and column name. This function is concurrency safe.
func (f *File) GetColStyle(sheet, col string) (int, error) {
var styleID int
colNum, err := ColumnNameToNumber(col)
@ -663,7 +674,7 @@ func (f *File) GetColStyle(sheet, col string) (int, error) {
}
// GetColWidth provides a function to get column width by given worksheet name
// and column name.
// and column name. This function is concurrency safe.
func (f *File) GetColWidth(sheet, col string) (float64, error) {
colNum, err := ColumnNameToNumber(col)
if err != nil {

View File

@ -1201,14 +1201,26 @@ func TestHSL(t *testing.T) {
assert.Equal(t, 0.0, hueToRGB(0, 0, 1.0/7))
assert.Equal(t, 0.0, hueToRGB(0, 0, 0.4))
assert.Equal(t, 0.0, hueToRGB(0, 0, 2.0/4))
t.Log(RGBToHSL(255, 255, 0))
h, s, l := RGBToHSL(0, 255, 255)
h, s, l := RGBToHSL(255, 255, 0)
assert.Equal(t, 0.16666666666666666, h)
assert.Equal(t, 1.0, s)
assert.Equal(t, 0.5, l)
h, s, l = RGBToHSL(0, 255, 255)
assert.Equal(t, 0.5, h)
assert.Equal(t, 1.0, s)
assert.Equal(t, 0.5, l)
t.Log(RGBToHSL(250, 100, 50))
t.Log(RGBToHSL(50, 100, 250))
t.Log(RGBToHSL(250, 50, 100))
h, s, l = RGBToHSL(250, 100, 50)
assert.Equal(t, 0.041666666666666664, h)
assert.Equal(t, 0.9523809523809524, s)
assert.Equal(t, 0.5882352941176471, l)
h, s, l = RGBToHSL(50, 100, 250)
assert.Equal(t, 0.625, h)
assert.Equal(t, 0.9523809523809524, s)
assert.Equal(t, 0.5882352941176471, l)
h, s, l = RGBToHSL(250, 50, 100)
assert.Equal(t, 0.9583333333333334, h)
assert.Equal(t, 0.9523809523809524, s)
assert.Equal(t, 0.5882352941176471, l)
}
func TestProtectSheet(t *testing.T) {

View File

@ -60,6 +60,8 @@ func (f *File) MergeCell(sheet, hCell, vCell string) error {
if err != nil {
return err
}
ws.Lock()
defer ws.Unlock()
ref := hCell + ":" + vCell
if ws.MergeCells != nil {
ws.MergeCells.Cells = append(ws.MergeCells.Cells, &xlsxMergeCell{Ref: ref, rect: rect})
@ -81,6 +83,8 @@ func (f *File) UnmergeCell(sheet string, hCell, vCell string) error {
if err != nil {
return err
}
ws.Lock()
defer ws.Unlock()
rect1, err := areaRefToCoordinates(hCell + ":" + vCell)
if err != nil {
return err

View File

@ -39,7 +39,7 @@ func parseFormatPictureSet(formatSet string) (*formatPicture, error) {
// AddPicture provides the method to add picture in a sheet by given picture
// format set (such as offset, scale, aspect ratio setting and print settings)
// and file path. For example:
// and file path. This function is concurrency safe. For example:
//
// package main
//
@ -469,7 +469,7 @@ func (f *File) getSheetRelationshipsTargetByID(sheet, rID string) string {
// GetPicture provides a function to get picture base name and raw content
// embed in spreadsheet by given worksheet and cell name. This function
// returns the file name in spreadsheet and file contents as []byte data
// types. For example:
// types. This function is concurrency safe. For example:
//
// f, err := excelize.OpenFile("Book1.xlsx")
// if err != nil {

View File

@ -238,7 +238,8 @@ func (rows *Rows) rowXMLHandler(rowIterator *rowXMLIterator, xmlElement *xml.Sta
}
// Rows returns a rows iterator, used for streaming reading data for a
// worksheet with a large data. For example:
// worksheet with a large data. This function is concurrency safe. For
// example:
//
// rows, err := f.Rows("Sheet1")
// if err != nil {

View File

@ -1005,8 +1005,9 @@ func parseFormatStyleSet(style interface{}) (*Style, error) {
return &fs, err
}
// NewStyle provides a function to create the style for cells by given JSON or
// structure pointer. Note that the color field uses RGB color code.
// NewStyle provides a function to create the style for cells by given
// structure pointer or JSON. This function is concurrency safe. Note that the
// color field uses RGB color code.
//
// The following shows the border styles sorted by excelize index number:
//
@ -2493,10 +2494,10 @@ func (f *File) GetCellStyle(sheet, axis string) (int, error) {
}
// SetCellStyle provides a function to add style attribute for cells by given
// worksheet name, coordinate area and style ID. Note that diagonalDown and
// diagonalUp type border should be use same color in the same coordinate
// area. SetCellStyle will overwrite the existing styles for the cell, it
// won't append or merge style with existing styles.
// worksheet name, coordinate area and style ID. This function is concurrency
// safe. Note that diagonalDown and diagonalUp type border should be use same
// color in the same coordinate area. SetCellStyle will overwrite the existing
// styles for the cell, it won't append or merge style with existing styles.
//
// For example create a borders of cell H9 on Sheet1:
//