♻️ Adjust addRiffCards/removeRiffCards implementation to be asynchronous transaction https://github.com/siyuan-note/siyuan/issues/7936

This commit is contained in:
Liang Ding 2023-04-09 23:00:09 +08:00
parent e5143a8474
commit 3e14b4f29c
No known key found for this signature in database
GPG key ID: 136F30F901A2231D
3 changed files with 58 additions and 104 deletions

View file

@ -216,13 +216,22 @@ func removeRiffCards(c *gin.Context) {
for _, blockID := range blockIDsArg {
blockIDs = append(blockIDs, blockID.(string))
}
err := model.RemoveFlashcardsByBlockIDs(deckID, blockIDs)
if nil != err {
ret.Code = -1
ret.Msg = err.Error()
return
transactions := []*model.Transaction{
{
DoOperations: []*model.Operation{
{
Action: "removeFlashcards",
DeckID: deckID,
BlockIDs: blockIDs,
},
},
},
}
model.PerformTransactions(&transactions)
model.WaitForWritingFiles()
if "" != deckID {
deck := model.Decks[deckID]
ret.Data = deckData(deck)
@ -245,13 +254,22 @@ func addRiffCards(c *gin.Context) {
for _, blockID := range blockIDsArg {
blockIDs = append(blockIDs, blockID.(string))
}
err := model.AddFlashcards(deckID, blockIDs)
if nil != err {
ret.Code = -1
ret.Msg = err.Error()
return
transactions := []*model.Transaction{
{
DoOperations: []*model.Operation{
{
Action: "addFlashcards",
DeckID: deckID,
BlockIDs: blockIDs,
},
},
},
}
model.PerformTransactions(&transactions)
model.WaitForWritingFiles()
deck := model.Decks[deckID]
ret.Data = deckData(deck)
}

View file

@ -456,95 +456,20 @@ func getAllDueFlashcards(reviewedCardIDs []string) (ret []*Flashcard) {
return
}
func RemoveFlashcardsByCardIDs(deckID string, cardIDs []string) (err error) {
func (tx *Transaction) doRemoveFlashcards(operation *Operation) (ret *TxErr) {
deckLock.Lock()
defer deckLock.Unlock()
if syncingStorages {
err = errors.New(Conf.Language(81))
ret = &TxErr{code: TxErrCodeDataIsSyncing}
return
}
var needRemoveDeckAttrBlockIDs []string
if "" == deckID {
// 在 All 卡包中移除
var affectedBlockIDs []string
for _, deck := range Decks {
changed := false
for _, cardID := range cardIDs {
card := deck.GetCard(cardID)
if nil == card {
continue
}
deckID := operation.DeckID
blockIDs := operation.BlockIDs
affectedBlockIDs = append(affectedBlockIDs, card.BlockID())
deck.RemoveCard(cardID)
changed = true
}
if changed {
if err = deck.Save(); nil != err {
return
}
}
// 检查刚刚移除的卡片关联的块是否还存在更多关联的卡片
affectedBlockIDs = gulu.Str.RemoveDuplicatedElem(affectedBlockIDs)
for _, blockID := range affectedBlockIDs {
moreRelatedCards := deck.GetCardsByBlockID(blockID)
if 1 > len(moreRelatedCards) {
needRemoveDeckAttrBlockIDs = append(needRemoveDeckAttrBlockIDs, blockID)
}
}
}
} else {
// 在指定卡包中移除
deck := Decks[deckID]
if nil == deck {
return
}
var affectedBlockIDs []string
for _, cardID := range cardIDs {
card := deck.GetCard(cardID)
if nil == card {
continue
}
affectedBlockIDs = append(affectedBlockIDs, card.BlockID())
deck.RemoveCard(cardID)
if err = deck.Save(); nil != err {
return
}
}
// 检查刚刚移除的卡片关联的块是否还存在更多关联的卡片
affectedBlockIDs = gulu.Str.RemoveDuplicatedElem(affectedBlockIDs)
for _, blockID := range affectedBlockIDs {
moreRelatedCards := deck.GetCardsByBlockID(blockID)
if 1 > len(moreRelatedCards) {
needRemoveDeckAttrBlockIDs = append(needRemoveDeckAttrBlockIDs, blockID)
}
}
}
if err = removeBlocksDeckAttr(needRemoveDeckAttrBlockIDs, deckID); nil != err {
return
}
return
}
func RemoveFlashcardsByBlockIDs(deckID string, blockIDs []string) (err error) {
deckLock.Lock()
defer deckLock.Unlock()
if syncingStorages {
err = errors.New(Conf.Language(81))
return
}
if err = removeBlocksDeckAttr(blockIDs, deckID); nil != err {
return
if err := tx.removeBlocksDeckAttr(blockIDs, deckID); nil != err {
return &TxErr{code: TxErrCodeWriteTree, msg: err.Error(), id: deckID}
}
if "" == deckID { // 支持在 All 卡包中移除闪卡 https://github.com/siyuan-note/siyuan/issues/7425
@ -557,7 +482,7 @@ func RemoveFlashcardsByBlockIDs(deckID string, blockIDs []string) (err error) {
return
}
func removeBlocksDeckAttr(blockIDs []string, deckID string) (err error) {
func (tx *Transaction) removeBlocksDeckAttr(blockIDs []string, deckID string) (err error) {
var rootIDs []string
blockRoots := map[string]string{}
for _, blockID := range blockIDs {
@ -577,7 +502,7 @@ func removeBlocksDeckAttr(blockIDs []string, deckID string) (err error) {
tree := trees[rootID]
if nil == tree {
tree, _ = loadTreeByBlockID(blockID)
tree, _ = tx.loadTree(blockID)
}
if nil == tree {
continue
@ -612,7 +537,7 @@ func removeBlocksDeckAttr(blockIDs []string, deckID string) (err error) {
node.SetIALAttr("custom-riff-decks", val)
}
if err = indexWriteJSONQueue(tree); nil != err {
if err = tx.writeTree(tree); nil != err {
return
}
@ -643,15 +568,18 @@ func removeFlashcardsByBlockIDs(blockIDs []string, deck *riff.Deck) {
}
}
func AddFlashcards(deckID string, blockIDs []string) (err error) {
func (tx *Transaction) doAddFlashcards(operation *Operation) (ret *TxErr) {
deckLock.Lock()
defer deckLock.Unlock()
if syncingStorages {
err = errors.New(Conf.Language(81))
ret = &TxErr{code: TxErrCodeDataIsSyncing}
return
}
deckID := operation.DeckID
blockIDs := operation.BlockIDs
blockRoots := map[string]string{}
for _, blockID := range blockIDs {
bt := treenode.GetBlockTree(blockID)
@ -668,7 +596,7 @@ func AddFlashcards(deckID string, blockIDs []string) (err error) {
tree := trees[rootID]
if nil == tree {
tree, _ = loadTreeByBlockID(blockID)
tree, _ = tx.loadTree(blockID)
}
if nil == tree {
continue
@ -691,8 +619,8 @@ func AddFlashcards(deckID string, blockIDs []string) (err error) {
val = strings.TrimSuffix(val, ",")
node.SetIALAttr("custom-riff-decks", val)
if err = indexWriteJSONQueue(tree); nil != err {
return
if err := tx.writeTree(tree); nil != err {
return &TxErr{code: TxErrCodeWriteTree, msg: err.Error(), id: deckID}
}
cache.PutBlockIAL(blockID, parse.IAL2Map(node.KramdownIAL))
@ -715,8 +643,8 @@ func AddFlashcards(deckID string, blockIDs []string) (err error) {
cardID := ast.NewNodeID()
deck.AddCard(cardID, blockID)
}
err = deck.Save()
if nil != err {
if err := deck.Save(); nil != err {
logging.LogErrorf("save deck [%s] failed: %s", deckID, err)
return
}

View file

@ -155,6 +155,7 @@ func PerformTransactions(transactions *[]*Transaction) {
const (
TxErrCodeBlockNotFound = 0
TxErrCodeDataIsSyncing = 1
TxErrCodeWriteTree = 2
TxErrWriteAttributeView = 3
)
@ -208,7 +209,11 @@ func performTx(tx *Transaction) (ret *TxErr) {
case "unfoldHeading":
ret = tx.doUnfoldHeading(op)
case "setAttrs":
ret = tx.setAttrs(op)
ret = tx.doSetAttrs(op)
case "addFlashcards":
ret = tx.doAddFlashcards(op)
case "removeFlashcards":
ret = tx.doRemoveFlashcards(op)
case "insertAttrViewBlock":
ret = tx.doInsertAttrViewBlock(op)
case "removeAttrViewBlock":
@ -927,7 +932,7 @@ func (tx *Transaction) doCreate(operation *Operation) (ret *TxErr) {
return
}
func (tx *Transaction) setAttrs(operation *Operation) (ret *TxErr) {
func (tx *Transaction) doSetAttrs(operation *Operation) (ret *TxErr) {
id := operation.ID
tree, err := tx.loadTree(id)
if nil != err {
@ -968,7 +973,7 @@ func (tx *Transaction) setAttrs(operation *Operation) (ret *TxErr) {
}
}
if err = indexWriteJSONQueue(tree); nil != err {
if err = tx.writeTree(tree); nil != err {
return
}
cache.PutBlockIAL(id, parse.IAL2Map(node.KramdownIAL))
@ -1007,6 +1012,9 @@ type Operation struct {
PreviousID string `json:"previousID"`
NextID string `json:"nextID"`
RetData interface{} `json:"retData"`
BlockIDs []string `json:"blockIDs"`
DeckID string `json:"deckID"` // 用于添加/删除闪卡
SrcIDs []string `json:"srcIDs"` // 用于将块拖拽到属性视图中
Name string `json:"name"` // 用于属性视图列名