oficina / sheets Public

Clone
git clone https://amadan.net/oficina/sheets

Plain git — no account needed to clone.

Download

Download this file

1package store
2
3import (
4 "amadan.net/oficina/sheets/internal/sheets/calc"
5 "errors"
6
7 "gorm.io/gorm"
8)
9
10const MaxCellBatch = 500
11
12type CellWrite struct {
13 Row, Col int
14 Raw string
15}
16
17var errCellBatch = errors.New("store: invalid cell batch")
18
19func (h *Handle) SetBatch(writes []CellWrite, actor uint64) (Report, error) {
20 if len(writes) == 0 || len(writes) > MaxCellBatch {
21 return Report{}, errCellBatch
22 }
23 seen := make(map[[2]int]bool, len(writes))
24 for _, w := range writes {
25 pos := [2]int{w.Row, w.Col}
26 if w.Row < 0 || w.Col < 0 || seen[pos] {
27 return Report{}, errCellBatch
28 }
29 seen[pos] = true
30 if _, _, err := contentNode(w.Raw); err != nil {
31 return Report{}, errCellBatch
32 }
33 }
34 h.mu.Lock()
35 defer h.mu.Unlock()
36
37 var staged *Handle
38 var result Report
39 err := h.db.Transaction(func(tx *gorm.DB) error {
40 var err error
41 staged, err = buildHandle(tx, h.sealer, h.tabID)
42 if err != nil {
43 return err
44 }
45 if staged.nextVersion < h.nextVersion {
46 staged.nextVersion = h.nextVersion
47 }
48 changed := make(map[CellCoord]ChangedCell)
49 direct := make(map[CellCoord]bool)
50 for _, w := range writes {
51 r, err := staged.EnsureRow(w.Row)
52 if err != nil {
53 return err
54 }
55 c, err := staged.EnsureCol(w.Col)
56 if err != nil {
57 return err
58 }
59 rep, err := staged.SetReport(r, c, w.Raw, actor)
60 if err != nil {
61 return err
62 }
63 if rep.Capped {
64 return errCellBatch
65 }
66 direct[CellCoord{r, c}] = true
67 result.Version = rep.Version
68 for _, cell := range rep.Cells {
69 changed[CellCoord{cell.RowID, cell.ColID}] = cell
70 }
71 if len(changed) > calc.MaxDirtyPerPass {
72 return errCellBatch
73 }
74 }
75 var count int64
76 if err := tx.Model(&Cell{}).Where("tab_id = ?", h.tabID).Count(&count).Error; err != nil {
77 return err
78 }
79 if count > MaxCellsPerTab {
80 return ErrTabTooLarge
81 }
82 for coord, cell := range changed {
83 cell.Derived = !direct[coord]
84 result.Cells = append(result.Cells, cell)
85 }
86 return nil
87 })
88 if err != nil {
89 return Report{}, err
90 }
91 h.graph, h.rawText, h.keyToIDs = staged.graph, staged.rawText, staged.keyToIDs
92 h.rowPos, h.colPos = staged.rowPos, staged.colPos
93 h.rowByPos, h.colByPos = staged.rowByPos, staged.colByPos
94 h.nextVersion = staged.nextVersion
95 result.Stamps = len(writes) // one SetReport, so one stamp, per write
96 return result, nil
97}
98