From 2f01f3224d3a92ba69123634a011101d3f605c0b Mon Sep 17 00:00:00 2001
From: Daniel <845765@qq.com>
Date: Mon, 4 Aug 2025 10:47:21 +0800
Subject: [PATCH 1/5] :art: Improve database field default filling
https://github.com/siyuan-note/siyuan/issues/11966
---
kernel/model/attribute_view.go | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go
index 4a168a4c6..df3eec596 100644
--- a/kernel/model/attribute_view.go
+++ b/kernel/model/attribute_view.go
@@ -79,6 +79,26 @@ func getAttrViewAddingBlockDefaultValues(attrView *av.AttributeView, view, group
filterKeyIDs[f.Column] = true
}
+ // 对库中存在模板字段的情况进行处理
+ existTemplateField := false
+ for _, keyValues := range attrView.KeyValues {
+ if av.KeyTypeTemplate == keyValues.Key.Type {
+ existTemplateField = true
+ break
+ }
+ }
+ if existTemplateField {
+ if nil != nearItem {
+ // 存在模板字段且存在临近项时从临近项获取新值
+ for _, keyValues := range attrView.KeyValues {
+ newValue := getNewValueByNearItem(nearItem, keyValues.Key, addingBlockID)
+ ret[keyValues.Key.ID] = newValue
+ }
+ } else { // 存在模板字段但不存在临近项时不生成任何新值
+ return
+ }
+ }
+
for _, filter := range view.Filters {
keyValues, _ := attrView.GetKeyValues(filter.Column)
if nil == keyValues {
@@ -87,8 +107,10 @@ func getAttrViewAddingBlockDefaultValues(attrView *av.AttributeView, view, group
var newValue *av.Value
if nil != nearItem {
+ // 存在临近项时优先通过临近项获取新值
newValue = getNewValueByNearItem(nearItem, keyValues.Key, addingBlockID)
} else {
+ // 不存在临近项时通过过滤条件计算新值
newValue = filter.GetAffectValue(keyValues.Key, addingBlockID)
}
if nil != newValue {
From bb989bcb3509dcf19b5d31ec0bc8e124c2ea22ea Mon Sep 17 00:00:00 2001
From: Daniel <845765@qq.com>
Date: Mon, 4 Aug 2025 11:09:36 +0800
Subject: [PATCH 2/5] :bug: Improve date filter
---
kernel/av/filter.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/av/filter.go b/kernel/av/filter.go
index d60735a30..7ec186445 100644
--- a/kernel/av/filter.go
+++ b/kernel/av/filter.go
@@ -632,13 +632,13 @@ func filterRelativeTime(valueMills int64, valueIsNotEmpty bool, operator FilterO
case FilterOperatorIsNotEqual:
return valueTime.Before(otherValueStart) || valueTime.After(otherValueEnd)
case FilterOperatorIsGreater:
- return valueTime.After(otherValueEnd) || valueTime.Equal(otherValueEnd)
+ return valueTime.After(otherValueStart)
case FilterOperatorIsGreaterOrEqual:
return valueTime.After(otherValueStart) || valueTime.Equal(otherValueStart)
case FilterOperatorIsLess:
return valueTime.Before(otherValueStart)
case FilterOperatorIsLessOrEqual:
- return valueTime.Before(otherValueEnd) || valueTime.Equal(otherValueEnd)
+ return valueTime.Before(otherValueStart) || valueTime.Equal(otherValueStart)
case FilterOperatorIsBetween:
if RelativeDateDirectionBefore == direction {
if RelativeDateDirectionBefore == direction2 {
From 9c99c6f8ef409c780d80f3305527ae5c23a672c3 Mon Sep 17 00:00:00 2001
From: Daniel <845765@qq.com>
Date: Mon, 4 Aug 2025 11:15:23 +0800
Subject: [PATCH 3/5] :art: Improve database field default filling
https://github.com/siyuan-note/siyuan/issues/11966
---
kernel/model/attribute_view.go | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go
index df3eec596..b4bc4aca5 100644
--- a/kernel/model/attribute_view.go
+++ b/kernel/model/attribute_view.go
@@ -79,22 +79,22 @@ func getAttrViewAddingBlockDefaultValues(attrView *av.AttributeView, view, group
filterKeyIDs[f.Column] = true
}
- // 对库中存在模板字段的情况进行处理
- existTemplateField := false
+ // 对库中存在模板字段和汇总字段的情况进行处理(尽量从临近项获取新值,获取不到的话直接返回)
+ existSpecialField := false
for _, keyValues := range attrView.KeyValues {
- if av.KeyTypeTemplate == keyValues.Key.Type {
- existTemplateField = true
+ if av.KeyTypeTemplate == keyValues.Key.Type || av.KeyTypeRollup == keyValues.Key.Type {
+ existSpecialField = true
break
}
}
- if existTemplateField {
+ if existSpecialField {
if nil != nearItem {
- // 存在模板字段且存在临近项时从临近项获取新值
+ // 存在临近项时从临近项获取新值
for _, keyValues := range attrView.KeyValues {
newValue := getNewValueByNearItem(nearItem, keyValues.Key, addingBlockID)
ret[keyValues.Key.ID] = newValue
}
- } else { // 存在模板字段但不存在临近项时不生成任何新值
+ } else { // 不存在临近项时不生成任何新值
return
}
}
From 3caeeaf29d90c900c36b74167ded803baee57b7c Mon Sep 17 00:00:00 2001
From: Daniel <845765@qq.com>
Date: Mon, 4 Aug 2025 11:24:46 +0800
Subject: [PATCH 4/5] :art: Improve database field default filling
https://github.com/siyuan-note/siyuan/issues/11966
---
kernel/model/attribute_view.go | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go
index b4bc4aca5..f2ac3daad 100644
--- a/kernel/model/attribute_view.go
+++ b/kernel/model/attribute_view.go
@@ -3157,6 +3157,11 @@ func addAttributeViewBlock(now int64, avID, blockID, groupID, previousBlockID, a
continue
}
+ if av.KeyTypeRollup == newValue.Type {
+ // 汇总字段的值是渲染时计算的,不需要添加到数据存储中
+ continue
+ }
+
if av.KeyTypeBlock == newValue.Type {
// 如果是主键的话前面已经添加过了,这里仅修改内容
blockValue.Block.Content = newValue.Block.Content
From bf465e5bbfeac8d00626845145f4eb77492024c4 Mon Sep 17 00:00:00 2001
From: Daniel <845765@qq.com>
Date: Mon, 4 Aug 2025 18:11:33 +0800
Subject: [PATCH 5/5] :recycle: Move .sy data parser to
https://github.com/siyuan-note/dataparser
---
kernel/filesys/json_parser.go | 287 -------------------------------
kernel/filesys/json_unmarshal.go | 25 ---
kernel/filesys/tree.go | 3 +-
kernel/go.mod | 7 +-
kernel/go.sum | 2 +
kernel/model/history.go | 4 +-
kernel/model/import.go | 3 +-
kernel/model/repository.go | 6 +-
kernel/model/tree.go | 3 +-
9 files changed, 16 insertions(+), 324 deletions(-)
delete mode 100644 kernel/filesys/json_parser.go
delete mode 100644 kernel/filesys/json_unmarshal.go
diff --git a/kernel/filesys/json_parser.go b/kernel/filesys/json_parser.go
deleted file mode 100644
index 6646cf604..000000000
--- a/kernel/filesys/json_parser.go
+++ /dev/null
@@ -1,287 +0,0 @@
-// SiYuan - Refactor your thinking
-// Copyright (c) 2020-present, b3log.org
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-
-package filesys
-
-import (
- "bytes"
- "strings"
-
- "github.com/88250/gulu"
- "github.com/88250/lute/ast"
- "github.com/88250/lute/editor"
- "github.com/88250/lute/parse"
- "github.com/siyuan-note/siyuan/kernel/treenode"
- "github.com/siyuan-note/siyuan/kernel/util"
-)
-
-func ParseJSONWithoutFix(jsonData []byte, options *parse.Options) (ret *parse.Tree, err error) {
- root := &ast.Node{}
- err = unmarshalJSON(jsonData, root)
- if err != nil {
- return
- }
-
- ret = &parse.Tree{Name: "", ID: root.ID, Root: &ast.Node{Type: ast.NodeDocument, ID: root.ID, Spec: root.Spec}, Context: &parse.Context{ParseOption: options}}
- ret.Root.KramdownIAL = parse.Map2IAL(root.Properties)
- ret.Root.SetIALAttr("type", "doc")
- ret.Context.Tip = ret.Root
- if nil == root.Children {
- return
- }
-
- idMap := map[string]bool{}
- for _, child := range root.Children {
- genTreeByJSON(child, ret, &idMap, nil, nil, true)
- }
- return
-}
-
-func ParseJSON(jsonData []byte, options *parse.Options) (ret *parse.Tree, needFix bool, err error) {
- root := &ast.Node{}
- err = unmarshalJSON(jsonData, root)
- if err != nil {
- return
- }
-
- ret = &parse.Tree{Name: "", ID: root.ID, Root: &ast.Node{Type: ast.NodeDocument, ID: root.ID, Spec: root.Spec}, Context: &parse.Context{ParseOption: options}}
- if icon := root.Properties["icon"]; "" != icon {
- // XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034
- if newIcon := util.FilterUploadEmojiFileName(icon); newIcon != icon {
- root.Properties["icon"] = newIcon
- needFix = true
- }
- }
-
- ret.Root.KramdownIAL = parse.Map2IAL(root.Properties)
- ret.Root.SetIALAttr("type", "doc")
- for _, kv := range ret.Root.KramdownIAL {
- if strings.Contains(kv[1], "\n") {
- val := kv[1]
- val = strings.ReplaceAll(val, "\n", editor.IALValEscNewLine)
- ret.Root.SetIALAttr(kv[0], val)
- needFix = true
- }
- }
-
- ret.Context.Tip = ret.Root
- if nil == root.Children {
- newPara := &ast.Node{Type: ast.NodeParagraph, ID: ast.NewNodeID()}
- newPara.SetIALAttr("id", newPara.ID)
- newPara.SetIALAttr("updated", newPara.ID[:14])
- ret.Root.AppendChild(newPara)
- needFix = true
- return
- }
-
- needMigrate2Spec1 := false
- idMap := map[string]bool{}
- for _, child := range root.Children {
- genTreeByJSON(child, ret, &idMap, &needFix, &needMigrate2Spec1, false)
- }
-
- if nil == ret.Root.FirstChild {
- // 如果是空文档的话挂一个空段落上去
- newP := treenode.NewParagraph("")
- ret.Root.AppendChild(newP)
- ret.Root.SetIALAttr("updated", newP.ID[:14])
- }
-
- if needMigrate2Spec1 {
- parse.NestedInlines2FlattedSpans(ret, false)
- needFix = true
- }
- return
-}
-
-func genTreeByJSON(node *ast.Node, tree *parse.Tree, idMap *map[string]bool, needFix, needMigrate2Spec1 *bool, ignoreFix bool) {
- node.Tokens, node.Type = gulu.Str.ToBytes(node.Data), ast.Str2NodeType(node.TypeStr)
- node.Data, node.TypeStr = "", ""
- node.KramdownIAL = parse.Map2IAL(node.Properties)
- node.Properties = nil
-
- if !ignoreFix {
- // 历史数据订正
-
- if -1 == node.Type {
- *needFix = true
- node.Type = ast.NodeParagraph
- node.AppendChild(&ast.Node{Type: ast.NodeText, Tokens: node.Tokens})
- node.Children = nil
- }
-
- switch node.Type {
- case ast.NodeList:
- if 1 > len(node.Children) {
- *needFix = true
- return // 忽略空列表
- }
- case ast.NodeListItem:
- if 1 > len(node.Children) {
- *needFix = true
- return // 忽略空列表项
- }
- case ast.NodeBlockquote:
- if 2 > len(node.Children) {
- *needFix = true
- return // 忽略空引述
- }
- case ast.NodeSuperBlock:
- if 4 > len(node.Children) {
- *needFix = true
- return // 忽略空超级块
- }
- case ast.NodeMathBlock:
- if 1 > len(node.Children) {
- *needFix = true
- return // 忽略空公式
- }
- case ast.NodeBlockQueryEmbed:
- if 1 > len(node.Children) {
- *needFix = true
- return // 忽略空查询嵌入块
- }
- case ast.NodeCodeBlock:
- if 4 > len(node.Children) {
- // https://ld246.com/article/1713689223067
- existCode := false
- for _, child := range node.Children {
- if ast.NodeCodeBlockCode.String() == child.TypeStr {
- existCode = true
- break
- }
- }
- if !existCode {
- *needFix = true
- return // 忽略空代码块
- }
- }
- }
-
- fixLegacyData(tree.Context.Tip, node, idMap, needFix, needMigrate2Spec1)
- }
-
- tree.Context.Tip.AppendChild(node)
- tree.Context.Tip = node
- defer tree.Context.ParentTip()
- if nil == node.Children {
- return
- }
- for _, child := range node.Children {
- genTreeByJSON(child, tree, idMap, needFix, needMigrate2Spec1, ignoreFix)
- }
- node.Children = nil
-}
-
-func fixLegacyData(tip, node *ast.Node, idMap *map[string]bool, needFix, needMigrate2Spec1 *bool) {
- if node.IsBlock() {
- if "" == node.ID {
- node.ID = ast.NewNodeID()
- node.SetIALAttr("id", node.ID)
- *needFix = true
- }
-
- if node.ID != node.IALAttr("id") {
- //某些情况下会导致 ID 和属性 id 不相同 https://ld246.com/article/1722826829447
- node.SetIALAttr("id", node.ID)
- *needFix = true
- }
-
- if 0 < len(node.Children) && ast.NodeBr.String() == node.Children[len(node.Children)-1].TypeStr {
- // 剔除块尾多余的软换行 https://github.com/siyuan-note/siyuan/issues/6191
- node.Children = node.Children[:len(node.Children)-1]
- *needFix = true
- }
- }
- if "" != node.ID {
- if _, ok := (*idMap)[node.ID]; ok {
- node.ID = ast.NewNodeID()
- node.SetIALAttr("id", node.ID)
- *needFix = true
- }
- (*idMap)[node.ID] = true
- }
-
- switch node.Type {
- case ast.NodeIFrame:
- if bytes.Contains(node.Tokens, gulu.Str.ToBytes("iframe-content")) {
- start := bytes.Index(node.Tokens, gulu.Str.ToBytes("