From 2d6900eafa9f7e71ce65a6e0c362286612d7a365 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sun, 31 Dec 2023 10:30:39 +0800 Subject: [PATCH] :art: Add Rollup column to database table view https://github.com/siyuan-note/siyuan/issues/9958 --- kernel/av/relation.go | 102 +++++++++++++++++++++++++++++++++ kernel/model/attribute_view.go | 98 ++++++++++++++++++++----------- 2 files changed, 165 insertions(+), 35 deletions(-) create mode 100644 kernel/av/relation.go diff --git a/kernel/av/relation.go b/kernel/av/relation.go new file mode 100644 index 000000000..f841a1ab2 --- /dev/null +++ b/kernel/av/relation.go @@ -0,0 +1,102 @@ +package av + +import ( + "os" + "path/filepath" + "sync" + + "github.com/88250/gulu" + "github.com/siyuan-note/filelock" + "github.com/siyuan-note/logging" + "github.com/siyuan-note/siyuan/kernel/util" + "github.com/vmihailenco/msgpack/v5" +) + +var ( + attributeViewRelationsLock = sync.Mutex{} +) + +func RemoveAvRel(avID, destAvID string) { + attributeViewRelationsLock.Lock() + defer attributeViewRelationsLock.Unlock() + + relations := filepath.Join(util.DataDir, "storage", "av", "relations.msgpack") + if !filelock.IsExist(relations) { + return + } + + data, err := filelock.ReadFile(relations) + if nil != err { + logging.LogErrorf("read attribute view relations failed: %s", err) + return + } + + avRels := map[string][]string{} + if err = msgpack.Unmarshal(data, &avRels); nil != err { + logging.LogErrorf("unmarshal attribute view relations failed: %s", err) + return + } + + destAvIDs := avRels[avID] + if nil == destAvIDs { + return + } + + var newAvIDs []string + for _, v := range destAvIDs { + if v != destAvID { + newAvIDs = append(newAvIDs, v) + } + } + avRels[avID] = newAvIDs + + data, err = msgpack.Marshal(avRels) + if nil != err { + logging.LogErrorf("marshal attribute view relations failed: %s", err) + return + } + if err = filelock.WriteFile(relations, data); nil != err { + logging.LogErrorf("write attribute view relations failed: %s", err) + return + } +} + +func UpsertAvRel(avID, destAvID string) { + attributeViewRelationsLock.Lock() + defer attributeViewRelationsLock.Unlock() + + avRelations := map[string][]string{} + relations := filepath.Join(util.DataDir, "storage", "av", "relations.msgpack") + if !filelock.IsExist(relations) { + if err := os.MkdirAll(filepath.Dir(relations), 0755); nil != err { + logging.LogErrorf("create attribute view dir failed: %s", err) + return + } + } else { + data, err := filelock.ReadFile(relations) + if nil != err { + logging.LogErrorf("read attribute view relations failed: %s", err) + return + } + + if err = msgpack.Unmarshal(data, &avRelations); nil != err { + logging.LogErrorf("unmarshal attribute view relations failed: %s", err) + return + } + } + + destAvIDs := avRelations[avID] + destAvIDs = append(destAvIDs, destAvID) + destAvIDs = gulu.Str.RemoveDuplicatedElem(destAvIDs) + avRelations[avID] = destAvIDs + + data, err := msgpack.Marshal(avRelations) + if nil != err { + logging.LogErrorf("marshal attribute view relations failed: %s", err) + return + } + if err = filelock.WriteFile(relations, data); nil != err { + logging.LogErrorf("write attribute view relations failed: %s", err) + return + } +} diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index cada7e4dd..cdb392517 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -980,27 +980,31 @@ func updateAttributeViewColRelation(operation *Operation) (err error) { srcRel := keyValues.Key.Relation // 已经设置过双向关联的话需要先断开双向关联 - if nil != srcRel && srcRel.IsTwoWay { - oldDestAv, _ := av.ParseAttributeView(srcRel.AvID) - if nil != oldDestAv { - isOldSameAv := oldDestAv.ID == destAv.ID - if isOldSameAv { - oldDestAv = destAv - } + if nil != srcRel { + if srcRel.IsTwoWay { + oldDestAv, _ := av.ParseAttributeView(srcRel.AvID) + if nil != oldDestAv { + isOldSameAv := oldDestAv.ID == destAv.ID + if isOldSameAv { + oldDestAv = destAv + } - oldDestKey, _ := oldDestAv.GetKey(srcRel.BackKeyID) - if nil != oldDestKey && nil != oldDestKey.Relation && oldDestKey.Relation.AvID == srcAv.ID && oldDestKey.Relation.IsTwoWay { - oldDestKey.Relation.IsTwoWay = false - oldDestKey.Relation.BackKeyID = "" - } + oldDestKey, _ := oldDestAv.GetKey(srcRel.BackKeyID) + if nil != oldDestKey && nil != oldDestKey.Relation && oldDestKey.Relation.AvID == srcAv.ID && oldDestKey.Relation.IsTwoWay { + oldDestKey.Relation.IsTwoWay = false + oldDestKey.Relation.BackKeyID = "" + } - if !isOldSameAv { - err = av.SaveAttributeView(oldDestAv) - if nil != err { - return + if !isOldSameAv { + err = av.SaveAttributeView(oldDestAv) + if nil != err { + return + } } } } + + av.RemoveAvRel(srcAv.ID, srcRel.AvID) } srcRel = &av.Relation{ @@ -1069,6 +1073,8 @@ func updateAttributeViewColRelation(operation *Operation) (err error) { err = av.SaveAttributeView(destAv) util.BroadcastByType("protyle", "refreshAttributeView", 0, "", map[string]interface{}{"id": destAv.ID}) } + + av.UpsertAvRel(srcAv.ID, destAv.ID) return } @@ -2116,31 +2122,53 @@ func removeAttributeViewColumn(operation *Operation) (err error) { } } - // 删除双向关联的目标列 - if nil != removedKey && nil != removedKey.Relation && removedKey.Relation.IsTwoWay { - destAv, _ := av.ParseAttributeView(removedKey.Relation.AvID) - if nil != destAv { - for i, keyValues := range destAv.KeyValues { - if keyValues.Key.ID == removedKey.Relation.BackKeyID { - destAv.KeyValues = append(destAv.KeyValues[:i], destAv.KeyValues[i+1:]...) - break - } - } + if nil != removedKey && av.KeyTypeRelation == removedKey.Type && nil != removedKey.Relation { + if removedKey.Relation.IsTwoWay { + // 删除双向关联的目标列 - for _, view := range destAv.Views { - switch view.LayoutType { - case av.LayoutTypeTable: - for i, column := range view.Table.Columns { - if column.ID == removedKey.Relation.BackKeyID { - view.Table.Columns = append(view.Table.Columns[:i], view.Table.Columns[i+1:]...) - break + destAv, _ := av.ParseAttributeView(removedKey.Relation.AvID) + if nil != destAv { + destAvRelSrcAv := false + for i, keyValues := range destAv.KeyValues { + if keyValues.Key.ID == removedKey.Relation.BackKeyID { + destAv.KeyValues = append(destAv.KeyValues[:i], destAv.KeyValues[i+1:]...) + continue + } + + if av.KeyTypeRelation == keyValues.Key.Type && keyValues.Key.Relation.AvID == attrView.ID { + destAvRelSrcAv = true + } + } + + for _, view := range destAv.Views { + switch view.LayoutType { + case av.LayoutTypeTable: + for i, column := range view.Table.Columns { + if column.ID == removedKey.Relation.BackKeyID { + view.Table.Columns = append(view.Table.Columns[:i], view.Table.Columns[i+1:]...) + break + } } } } + + av.SaveAttributeView(destAv) + util.BroadcastByType("protyle", "refreshAttributeView", 0, "", map[string]interface{}{"id": destAv.ID}) + + if !destAvRelSrcAv { + av.RemoveAvRel(destAv.ID, attrView.ID) + } } - av.SaveAttributeView(destAv) - util.BroadcastByType("protyle", "refreshAttributeView", 0, "", map[string]interface{}{"id": destAv.ID}) + srcAvRelDestAv := false + for _, keyValues := range attrView.KeyValues { + if av.KeyTypeRelation == keyValues.Key.Type && keyValues.Key.Relation.AvID == removedKey.Relation.AvID { + srcAvRelDestAv = true + } + } + if !srcAvRelDestAv { + av.RemoveAvRel(attrView.ID, removedKey.Relation.AvID) + } } }