Skip to content

Commit 9d4c2e6

Browse files
JackMin1314chenwang
and
chenwang
authored
This closes qax-os#1825, made AddDataValidation and DeleteDataValidation functions concurrency safe (qax-os#1828)
- Remove the receiver of internal coordinatesToRangeRef, squashSqref and flatSqref functions - Update unit tests Co-authored-by: chenwang <chenwang@shinsson.com>
1 parent 7b4da39 commit 9d4c2e6

9 files changed

+43
-26
lines changed

adjust.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ func (f *File) adjustCellRef(ref string, dir adjustDirection, num, offset int) (
267267
coordinates[3] += offset
268268
}
269269
}
270-
ref, err = f.coordinatesToRangeRef(coordinates)
270+
ref, err = coordinatesToRangeRef(coordinates)
271271
return ref, delete, err
272272
}
273273

@@ -666,7 +666,7 @@ func (f *File) adjustTable(ws *xlsxWorksheet, sheet string, dir adjustDirection,
666666
idx--
667667
continue
668668
}
669-
t.Ref, _ = f.coordinatesToRangeRef([]int{x1, y1, x2, y2})
669+
t.Ref, _ = coordinatesToRangeRef([]int{x1, y1, x2, y2})
670670
if t.AutoFilter != nil {
671671
t.AutoFilter.Ref = t.Ref
672672
}
@@ -706,7 +706,7 @@ func (f *File) adjustAutoFilter(ws *xlsxWorksheet, sheet string, dir adjustDirec
706706
coordinates = f.adjustAutoFilterHelper(dir, coordinates, num, offset)
707707
x1, y1, x2, y2 = coordinates[0], coordinates[1], coordinates[2], coordinates[3]
708708

709-
ws.AutoFilter.Ref, err = f.coordinatesToRangeRef([]int{x1, y1, x2, y2})
709+
ws.AutoFilter.Ref, err = coordinatesToRangeRef([]int{x1, y1, x2, y2})
710710
return err
711711
}
712712

@@ -773,7 +773,7 @@ func (f *File) adjustMergeCells(ws *xlsxWorksheet, sheet string, dir adjustDirec
773773
continue
774774
}
775775
mergedCells.rect = []int{x1, y1, x2, y2}
776-
if mergedCells.Ref, err = f.coordinatesToRangeRef([]int{x1, y1, x2, y2}); err != nil {
776+
if mergedCells.Ref, err = coordinatesToRangeRef([]int{x1, y1, x2, y2}); err != nil {
777777
return err
778778
}
779779
}

cell_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ func TestConcurrency(t *testing.T) {
8888
visible, err := f.GetColVisible("Sheet1", "A")
8989
assert.NoError(t, err)
9090
assert.Equal(t, true, visible)
91+
// Concurrency add data validation
92+
dv := NewDataValidation(true)
93+
dv.Sqref = fmt.Sprintf("A%d:B%d", val, val)
94+
dv.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorGreaterThan)
95+
dv.SetInput(fmt.Sprintf("title:%d", val), strconv.Itoa(val))
96+
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
97+
// Concurrency delete data validation with reference sequence
98+
assert.NoError(t, f.DeleteDataValidation("Sheet1", dv.Sqref))
9199
wg.Done()
92100
}(i, t)
93101
}
@@ -97,6 +105,10 @@ func TestConcurrency(t *testing.T) {
97105
t.Error(err)
98106
}
99107
assert.Equal(t, "1", val)
108+
// Test the length of data validation
109+
dataValidations, err := f.GetDataValidations("Sheet1")
110+
assert.NoError(t, err)
111+
assert.Len(t, dataValidations, 0)
100112
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestConcurrency.xlsx")))
101113
assert.NoError(t, f.Close())
102114
}

datavalidation.go

+15-9
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,9 @@ func (dv *DataValidation) SetSqref(sqref string) {
222222
}
223223

224224
// AddDataValidation provides set data validation on a range of the worksheet
225-
// by given data validation object and worksheet name. The data validation
226-
// object can be created by NewDataValidation function.
225+
// by given data validation object and worksheet name. This function is
226+
// concurrency safe. The data validation object can be created by
227+
// NewDataValidation function.
227228
//
228229
// Example 1, set data validation on Sheet1!A1:B2 with validation criteria
229230
// settings, show error alert after invalid data is entered with "Stop" style
@@ -256,6 +257,8 @@ func (f *File) AddDataValidation(sheet string, dv *DataValidation) error {
256257
if err != nil {
257258
return err
258259
}
260+
ws.mu.Lock()
261+
defer ws.mu.Unlock()
259262
if nil == ws.DataValidations {
260263
ws.DataValidations = new(xlsxDataValidations)
261264
}
@@ -323,28 +326,31 @@ func (f *File) GetDataValidations(sheet string) ([]*DataValidation, error) {
323326
}
324327

325328
// DeleteDataValidation delete data validation by given worksheet name and
326-
// reference sequence. All data validations in the worksheet will be deleted
329+
// reference sequence. This function is concurrency safe.
330+
// All data validations in the worksheet will be deleted
327331
// if not specify reference sequence parameter.
328332
func (f *File) DeleteDataValidation(sheet string, sqref ...string) error {
329333
ws, err := f.workSheetReader(sheet)
330334
if err != nil {
331335
return err
332336
}
337+
ws.mu.Lock()
338+
defer ws.mu.Unlock()
333339
if ws.DataValidations == nil {
334340
return nil
335341
}
336342
if sqref == nil {
337343
ws.DataValidations = nil
338344
return nil
339345
}
340-
delCells, err := f.flatSqref(sqref[0])
346+
delCells, err := flatSqref(sqref[0])
341347
if err != nil {
342348
return err
343349
}
344350
dv := ws.DataValidations
345351
for i := 0; i < len(dv.DataValidation); i++ {
346352
var applySqref []string
347-
colCells, err := f.flatSqref(dv.DataValidation[i].Sqref)
353+
colCells, err := flatSqref(dv.DataValidation[i].Sqref)
348354
if err != nil {
349355
return err
350356
}
@@ -357,7 +363,7 @@ func (f *File) DeleteDataValidation(sheet string, sqref ...string) error {
357363
}
358364
}
359365
for _, col := range colCells {
360-
applySqref = append(applySqref, f.squashSqref(col)...)
366+
applySqref = append(applySqref, squashSqref(col)...)
361367
}
362368
dv.DataValidation[i].Sqref = strings.Join(applySqref, " ")
363369
if len(applySqref) == 0 {
@@ -373,7 +379,7 @@ func (f *File) DeleteDataValidation(sheet string, sqref ...string) error {
373379
}
374380

375381
// squashSqref generates cell reference sequence by given cells coordinates list.
376-
func (f *File) squashSqref(cells [][]int) []string {
382+
func squashSqref(cells [][]int) []string {
377383
if len(cells) == 1 {
378384
cell, _ := CoordinatesToCellName(cells[0][0], cells[0][1])
379385
return []string{cell}
@@ -384,7 +390,7 @@ func (f *File) squashSqref(cells [][]int) []string {
384390
l, r := 0, 0
385391
for i := 1; i < len(cells); i++ {
386392
if cells[i][0] == cells[r][0] && cells[i][1]-cells[r][1] > 1 {
387-
ref, _ := f.coordinatesToRangeRef(append(cells[l], cells[r]...))
393+
ref, _ := coordinatesToRangeRef(append(cells[l], cells[r]...))
388394
if l == r {
389395
ref, _ = CoordinatesToCellName(cells[l][0], cells[l][1])
390396
}
@@ -394,7 +400,7 @@ func (f *File) squashSqref(cells [][]int) []string {
394400
r++
395401
}
396402
}
397-
ref, _ := f.coordinatesToRangeRef(append(cells[l], cells[r]...))
403+
ref, _ := coordinatesToRangeRef(append(cells[l], cells[r]...))
398404
if l == r {
399405
ref, _ = CoordinatesToCellName(cells[l][0], cells[l][1])
400406
}

lib.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ func sortCoordinates(coordinates []int) error {
323323

324324
// coordinatesToRangeRef provides a function to convert a pair of coordinates
325325
// to range reference.
326-
func (f *File) coordinatesToRangeRef(coordinates []int, abs ...bool) (string, error) {
326+
func coordinatesToRangeRef(coordinates []int, abs ...bool) (string, error) {
327327
if len(coordinates) != 4 {
328328
return "", ErrCoordinates
329329
}
@@ -360,7 +360,7 @@ func (f *File) getDefinedNameRefTo(definedNameName, currentSheet string) (refTo
360360
}
361361

362362
// flatSqref convert reference sequence to cell reference list.
363-
func (f *File) flatSqref(sqref string) (cells map[int][][]int, err error) {
363+
func flatSqref(sqref string) (cells map[int][][]int, err error) {
364364
var coordinates []int
365365
cells = make(map[int][][]int)
366366
for _, ref := range strings.Fields(sqref) {

lib_test.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,13 @@ func TestCoordinatesToCellName_Error(t *testing.T) {
218218
}
219219

220220
func TestCoordinatesToRangeRef(t *testing.T) {
221-
f := NewFile()
222-
_, err := f.coordinatesToRangeRef([]int{})
221+
_, err := coordinatesToRangeRef([]int{})
223222
assert.EqualError(t, err, ErrCoordinates.Error())
224-
_, err = f.coordinatesToRangeRef([]int{1, -1, 1, 1})
223+
_, err = coordinatesToRangeRef([]int{1, -1, 1, 1})
225224
assert.Equal(t, newCoordinatesToCellNameError(1, -1), err)
226-
_, err = f.coordinatesToRangeRef([]int{1, 1, 1, -1})
225+
_, err = coordinatesToRangeRef([]int{1, 1, 1, -1})
227226
assert.Equal(t, newCoordinatesToCellNameError(1, -1), err)
228-
ref, err := f.coordinatesToRangeRef([]int{1, 1, 1, 1})
227+
ref, err := coordinatesToRangeRef([]int{1, 1, 1, 1})
229228
assert.NoError(t, err)
230229
assert.EqualValues(t, ref, "A1:A1")
231230
}

rows.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ func (f *File) duplicateConditionalFormat(ws *xlsxWorksheet, sheet string, row,
705705
x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3]
706706
if y1 == y2 && y1 == row {
707707
cfCopy := deepcopy.Copy(*cf).(xlsxConditionalFormatting)
708-
if cfCopy.SQRef, err = f.coordinatesToRangeRef([]int{x1, row2, x2, row2}, abs); err != nil {
708+
if cfCopy.SQRef, err = coordinatesToRangeRef([]int{x1, row2, x2, row2}, abs); err != nil {
709709
return err
710710
}
711711
cfs = append(cfs, &cfCopy)
@@ -736,7 +736,7 @@ func (f *File) duplicateDataValidations(ws *xlsxWorksheet, sheet string, row, ro
736736
x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3]
737737
if y1 == y2 && y1 == row {
738738
dvCopy := deepcopy.Copy(*dv).(xlsxDataValidation)
739-
if dvCopy.Sqref, err = f.coordinatesToRangeRef([]int{x1, row2, x2, row2}, abs); err != nil {
739+
if dvCopy.Sqref, err = coordinatesToRangeRef([]int{x1, row2, x2, row2}, abs); err != nil {
740740
return err
741741
}
742742
dvs = append(dvs, &dvCopy)

sheet.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2014,7 +2014,7 @@ func (f *File) SetSheetDimension(sheet string, rangeRef string) error {
20142014
return err
20152015
}
20162016
_ = sortCoordinates(coordinates)
2017-
ref, err := f.coordinatesToRangeRef(coordinates)
2017+
ref, err := coordinatesToRangeRef(coordinates)
20182018
ws.Dimension = &xlsxDimension{Ref: ref}
20192019
return err
20202020
}

stream.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ func (sw *StreamWriter) AddTable(table *Table) error {
184184
}
185185

186186
// Correct table reference range, such correct C1:B3 to B1:C3.
187-
ref, err := sw.file.coordinatesToRangeRef(coordinates)
187+
ref, err := coordinatesToRangeRef(coordinates)
188188
if err != nil {
189189
return err
190190
}

table.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ func (f *File) addTable(sheet, tableXML string, x1, y1, x2, y2, i int, opts *Tab
350350
y1++
351351
}
352352
// Correct table range reference, such correct C1:B3 to B1:C3.
353-
ref, err := f.coordinatesToRangeRef([]int{x1, y1, x2, y2})
353+
ref, err := coordinatesToRangeRef([]int{x1, y1, x2, y2})
354354
if err != nil {
355355
return err
356356
}
@@ -463,7 +463,7 @@ func (f *File) AutoFilter(sheet, rangeRef string, opts []AutoFilterOptions) erro
463463
}
464464
_ = sortCoordinates(coordinates)
465465
// Correct reference range, such correct C1:B3 to B1:C3.
466-
ref, _ := f.coordinatesToRangeRef(coordinates, true)
466+
ref, _ := coordinatesToRangeRef(coordinates, true)
467467
wb, err := f.workbookReader()
468468
if err != nil {
469469
return err

0 commit comments

Comments
 (0)