🐛 Database cannot filter out rows with relations that are empty or not empty Fix https://github.com/siyuan-note/siyuan/issues/10601

This commit is contained in:
Daniel 2024-03-13 23:23:52 +08:00
parent cc9aed6aec
commit e02e4daa1c
No known key found for this signature in database
GPG key ID: 86211BA83DF03017
3 changed files with 797 additions and 773 deletions

View file

@ -17,6 +17,9 @@
package av package av
import ( import (
"strings"
"time"
"github.com/siyuan-note/siyuan/kernel/util" "github.com/siyuan-note/siyuan/kernel/util"
) )
@ -75,6 +78,557 @@ const (
FilterOperatorIsFalse FilterOperator = "Is false" FilterOperatorIsFalse FilterOperator = "Is false"
) )
func (value *Value) Filter(filter *ViewFilter, attrView *AttributeView, rowID string) bool {
if nil == filter || (nil == filter.Value && nil == filter.RelativeDate) {
return true
}
if nil != filter.Value && value.Type != filter.Value.Type {
// 由于字段类型被用户编辑过导致和过滤器值类型不匹配,该情况下不过滤
return true
}
if nil != value.Rollup && KeyTypeRollup == value.Type && nil != filter && nil != filter.Value && KeyTypeRollup == filter.Value.Type &&
nil != filter.Value.Rollup && 0 < len(filter.Value.Rollup.Contents) {
// 单独处理汇总类型的比较
// 处理为空和不为空
switch filter.Operator {
case FilterOperatorIsEmpty:
return 0 == len(value.Rollup.Contents)
case FilterOperatorIsNotEmpty:
return 0 != len(value.Rollup.Contents)
}
// 处理值比较
key, _ := attrView.GetKey(value.KeyID)
if nil == key {
return false
}
relKey, _ := attrView.GetKey(key.Rollup.RelationKeyID)
if nil == relKey {
return false
}
relVal := attrView.GetValue(relKey.ID, rowID)
if nil == relVal || nil == relVal.Relation {
return false
}
destAv, _ := ParseAttributeView(relKey.Relation.AvID)
if nil == destAv {
return false
}
for _, blockID := range relVal.Relation.BlockIDs {
destVal := destAv.GetValue(key.Rollup.KeyID, blockID)
if nil == destVal {
continue
}
if destVal.filter(filter.Value.Rollup.Contents[0], filter.RelativeDate, filter.RelativeDate2, filter.Operator) {
return true
}
}
return false
}
if nil != value.Relation && KeyTypeRelation == value.Type && 0 < len(value.Relation.Contents) && nil != filter && nil != filter.Value && KeyTypeRelation == filter.Value.Type &&
nil != filter.Value.Relation && 0 < len(filter.Value.Relation.BlockIDs) {
// 单独处理关联类型的比较
for _, relationValue := range value.Relation.Contents {
filterValue := &Value{Type: KeyTypeBlock, Block: &ValueBlock{Content: filter.Value.Relation.BlockIDs[0]}}
if relationValue.filter(filterValue, filter.RelativeDate, filter.RelativeDate2, filter.Operator) {
return true
}
}
return false
}
return value.filter(filter.Value, filter.RelativeDate, filter.RelativeDate2, filter.Operator)
}
func (value *Value) filter(other *Value, relativeDate, relativeDate2 *RelativeDate, operator FilterOperator) bool {
switch value.Type {
case KeyTypeBlock:
if nil != value.Block && nil != other && nil != other.Block {
switch operator {
case FilterOperatorIsEqual:
return value.Block.Content == other.Block.Content
case FilterOperatorIsNotEqual:
return value.Block.Content != other.Block.Content
case FilterOperatorContains:
return strings.Contains(value.Block.Content, other.Block.Content)
case FilterOperatorDoesNotContain:
return !strings.Contains(value.Block.Content, other.Block.Content)
case FilterOperatorStartsWith:
return strings.HasPrefix(value.Block.Content, other.Block.Content)
case FilterOperatorEndsWith:
return strings.HasSuffix(value.Block.Content, other.Block.Content)
case FilterOperatorIsEmpty:
return "" == strings.TrimSpace(value.Block.Content)
case FilterOperatorIsNotEmpty:
return "" != strings.TrimSpace(value.Block.Content)
}
}
case KeyTypeText:
if nil != value.Text && nil != other && nil != other.Text {
switch operator {
case FilterOperatorIsEqual:
if "" == strings.TrimSpace(other.Text.Content) {
return true
}
return value.Text.Content == other.Text.Content
case FilterOperatorIsNotEqual:
if "" == strings.TrimSpace(other.Text.Content) {
return true
}
return value.Text.Content != other.Text.Content
case FilterOperatorContains:
if "" == strings.TrimSpace(other.Text.Content) {
return true
}
return strings.Contains(value.Text.Content, other.Text.Content)
case FilterOperatorDoesNotContain:
if "" == strings.TrimSpace(other.Text.Content) {
return true
}
return !strings.Contains(value.Text.Content, other.Text.Content)
case FilterOperatorStartsWith:
if "" == strings.TrimSpace(other.Text.Content) {
return true
}
return strings.HasPrefix(value.Text.Content, other.Text.Content)
case FilterOperatorEndsWith:
if "" == strings.TrimSpace(other.Text.Content) {
return true
}
return strings.HasSuffix(value.Text.Content, other.Text.Content)
case FilterOperatorIsEmpty:
return "" == strings.TrimSpace(value.Text.Content)
case FilterOperatorIsNotEmpty:
return "" != strings.TrimSpace(value.Text.Content)
}
}
case KeyTypeNumber:
if nil != value.Number && nil != other && nil != other.Number {
switch operator {
case FilterOperatorIsEqual:
if !other.Number.IsNotEmpty {
return true
}
return value.Number.Content == other.Number.Content
case FilterOperatorIsNotEqual:
if !other.Number.IsNotEmpty {
return true
}
return value.Number.Content != other.Number.Content
case FilterOperatorIsGreater:
return value.Number.Content > other.Number.Content
case FilterOperatorIsGreaterOrEqual:
return value.Number.Content >= other.Number.Content
case FilterOperatorIsLess:
return value.Number.Content < other.Number.Content
case FilterOperatorIsLessOrEqual:
return value.Number.Content <= other.Number.Content
case FilterOperatorIsEmpty:
return !value.Number.IsNotEmpty
case FilterOperatorIsNotEmpty:
return value.Number.IsNotEmpty
}
}
case KeyTypeDate:
if nil != value.Date {
if nil != relativeDate {
// 使用相对时间比较
count := relativeDate.Count
unit := relativeDate.Unit
direction := relativeDate.Direction
relativeTimeStart, relativeTimeEnd := calcRelativeTimeRegion(count, unit, direction)
_, relativeTimeEnd2 := calcRelativeTimeRegion(relativeDate2.Count, relativeDate2.Unit, relativeDate2.Direction)
return filterTime(value.Date.Content, value.Date.IsNotEmpty, relativeTimeStart, relativeTimeEnd, relativeTimeEnd2, operator)
} else { // 使用具体时间比较
if nil == other.Date {
return true
}
otherTime := time.UnixMilli(other.Date.Content)
otherStart := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 0, 0, 0, 0, otherTime.Location())
otherEnd := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 23, 59, 59, 999999999, otherTime.Location())
return filterTime(value.Date.Content, value.Date.IsNotEmpty, otherStart, otherEnd, time.Now(), operator)
}
}
case KeyTypeCreated:
if nil != value.Created {
if nil != relativeDate {
// 使用相对时间比较
count := relativeDate.Count
unit := relativeDate.Unit
direction := relativeDate.Direction
relativeTimeStart, relativeTimeEnd := calcRelativeTimeRegion(count, unit, direction)
return filterTime(value.Created.Content, true, relativeTimeStart, relativeTimeEnd, time.Now(), operator)
} else { // 使用具体时间比较
if nil == other.Created {
return true
}
otherTime := time.UnixMilli(other.Created.Content)
otherStart := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 0, 0, 0, 0, otherTime.Location())
otherEnd := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 23, 59, 59, 999999999, otherTime.Location())
return filterTime(value.Created.Content, value.Created.IsNotEmpty, otherStart, otherEnd, time.Now(), operator)
}
}
case KeyTypeUpdated:
if nil != value.Updated {
if nil != relativeDate {
// 使用相对时间比较
count := relativeDate.Count
unit := relativeDate.Unit
direction := relativeDate.Direction
relativeTimeStart, relativeTimeEnd := calcRelativeTimeRegion(count, unit, direction)
return filterTime(value.Updated.Content, true, relativeTimeStart, relativeTimeEnd, time.Now(), operator)
} else { // 使用具体时间比较
if nil == other.Updated {
return true
}
otherTime := time.UnixMilli(other.Updated.Content)
otherStart := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 0, 0, 0, 0, otherTime.Location())
otherEnd := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 23, 59, 59, 999999999, otherTime.Location())
return filterTime(value.Updated.Content, value.Updated.IsNotEmpty, otherStart, otherEnd, time.Now(), operator)
}
}
case KeyTypeSelect, KeyTypeMSelect:
if nil != value.MSelect {
if nil != other && nil != other.MSelect {
switch operator {
case FilterOperatorIsEqual, FilterOperatorContains:
contains := false
for _, v := range value.MSelect {
for _, v2 := range other.MSelect {
if v.Content == v2.Content {
contains = true
break
}
}
}
return contains
case FilterOperatorIsNotEqual, FilterOperatorDoesNotContain:
contains := false
for _, v := range value.MSelect {
for _, v2 := range other.MSelect {
if v.Content == v2.Content {
contains = true
break
}
}
}
return !contains
case FilterOperatorIsEmpty:
return 0 == len(value.MSelect) || 1 == len(value.MSelect) && "" == value.MSelect[0].Content
case FilterOperatorIsNotEmpty:
return 0 != len(value.MSelect) && !(1 == len(value.MSelect) && "" == value.MSelect[0].Content)
}
return false
}
// 没有设置比较值
switch operator {
case FilterOperatorIsEqual, FilterOperatorIsNotEqual, FilterOperatorContains, FilterOperatorDoesNotContain:
return true
case FilterOperatorIsEmpty:
return 0 == len(value.MSelect) || 1 == len(value.MSelect) && "" == value.MSelect[0].Content
case FilterOperatorIsNotEmpty:
return 0 != len(value.MSelect) && !(1 == len(value.MSelect) && "" == value.MSelect[0].Content)
}
}
case KeyTypeURL:
if nil != value.URL && nil != other && nil != other.URL {
switch operator {
case FilterOperatorIsEqual:
return value.URL.Content == other.URL.Content
case FilterOperatorIsNotEqual:
return value.URL.Content != other.URL.Content
case FilterOperatorContains:
return strings.Contains(value.URL.Content, other.URL.Content)
case FilterOperatorDoesNotContain:
return !strings.Contains(value.URL.Content, other.URL.Content)
case FilterOperatorStartsWith:
return strings.HasPrefix(value.URL.Content, other.URL.Content)
case FilterOperatorEndsWith:
return strings.HasSuffix(value.URL.Content, other.URL.Content)
case FilterOperatorIsEmpty:
return "" == strings.TrimSpace(value.URL.Content)
case FilterOperatorIsNotEmpty:
return "" != strings.TrimSpace(value.URL.Content)
}
}
case KeyTypeEmail:
if nil != value.Email && nil != other && nil != other.Email {
switch operator {
case FilterOperatorIsEqual:
return value.Email.Content == other.Email.Content
case FilterOperatorIsNotEqual:
return value.Email.Content != other.Email.Content
case FilterOperatorContains:
return strings.Contains(value.Email.Content, other.Email.Content)
case FilterOperatorDoesNotContain:
return !strings.Contains(value.Email.Content, other.Email.Content)
case FilterOperatorStartsWith:
return strings.HasPrefix(value.Email.Content, other.Email.Content)
case FilterOperatorEndsWith:
return strings.HasSuffix(value.Email.Content, other.Email.Content)
case FilterOperatorIsEmpty:
return "" == strings.TrimSpace(value.Email.Content)
case FilterOperatorIsNotEmpty:
return "" != strings.TrimSpace(value.Email.Content)
}
}
case KeyTypePhone:
if nil != value.Phone && nil != other && nil != other.Phone {
switch operator {
case FilterOperatorIsEqual:
return value.Phone.Content == other.Phone.Content
case FilterOperatorIsNotEqual:
return value.Phone.Content != other.Phone.Content
case FilterOperatorContains:
return strings.Contains(value.Phone.Content, other.Phone.Content)
case FilterOperatorDoesNotContain:
return !strings.Contains(value.Phone.Content, other.Phone.Content)
case FilterOperatorStartsWith:
return strings.HasPrefix(value.Phone.Content, other.Phone.Content)
case FilterOperatorEndsWith:
return strings.HasSuffix(value.Phone.Content, other.Phone.Content)
case FilterOperatorIsEmpty:
return "" == strings.TrimSpace(value.Phone.Content)
case FilterOperatorIsNotEmpty:
return "" != strings.TrimSpace(value.Phone.Content)
}
}
case KeyTypeMAsset:
if nil != value.MAsset && nil != other && nil != other.MAsset && 0 < len(value.MAsset) && 0 < len(other.MAsset) {
switch operator {
case FilterOperatorIsEqual, FilterOperatorContains:
contains := false
for _, v := range value.MAsset {
for _, v2 := range other.MAsset {
if v.Content == v2.Content {
contains = true
break
}
}
}
return contains
case FilterOperatorIsNotEqual, FilterOperatorDoesNotContain:
contains := false
for _, v := range value.MAsset {
for _, v2 := range other.MAsset {
if v.Content == v2.Content {
contains = true
break
}
}
}
return !contains
case FilterOperatorIsEmpty:
return 0 == len(value.MAsset) || 1 == len(value.MAsset) && "" == value.MAsset[0].Content
case FilterOperatorIsNotEmpty:
return 0 != len(value.MAsset) && !(1 == len(value.MAsset) && "" == value.MAsset[0].Content)
}
}
case KeyTypeTemplate:
if nil != value.Template && nil != other && nil != other.Template {
switch operator {
case FilterOperatorIsEqual:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return value.Template.Content == other.Template.Content
case FilterOperatorIsNotEqual:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return value.Template.Content != other.Template.Content
case FilterOperatorIsGreater:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return value.Template.Content > other.Template.Content
case FilterOperatorIsGreaterOrEqual:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return value.Template.Content >= other.Template.Content
case FilterOperatorIsLess:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return value.Template.Content < other.Template.Content
case FilterOperatorIsLessOrEqual:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return value.Template.Content <= other.Template.Content
case FilterOperatorContains:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return strings.Contains(value.Template.Content, other.Template.Content)
case FilterOperatorDoesNotContain:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return !strings.Contains(value.Template.Content, other.Template.Content)
case FilterOperatorStartsWith:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return strings.HasPrefix(value.Template.Content, other.Template.Content)
case FilterOperatorEndsWith:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return strings.HasSuffix(value.Template.Content, other.Template.Content)
case FilterOperatorIsEmpty:
return "" == strings.TrimSpace(value.Template.Content)
case FilterOperatorIsNotEmpty:
return "" != strings.TrimSpace(value.Template.Content)
}
}
case KeyTypeCheckbox:
if nil != value.Checkbox {
switch operator {
case FilterOperatorIsTrue:
return value.Checkbox.Checked
case FilterOperatorIsFalse:
return !value.Checkbox.Checked
}
}
}
switch operator {
case FilterOperatorIsEmpty:
return value.IsEmpty()
case FilterOperatorIsNotEmpty:
return !value.IsEmpty()
}
return false
}
func filterTime(valueMills int64, valueIsNotEmpty bool, otherValueStart, otherValueEnd, otherValueEnd2 time.Time, operator FilterOperator) bool {
valueTime := time.UnixMilli(valueMills)
switch operator {
case FilterOperatorIsEqual:
return (valueTime.After(otherValueStart) || valueTime.Equal(otherValueStart)) && valueTime.Before(otherValueEnd)
case FilterOperatorIsNotEqual:
return valueTime.Before(otherValueStart) || valueTime.After(otherValueEnd)
case FilterOperatorIsGreater:
return valueTime.After(otherValueEnd) || valueTime.Equal(otherValueEnd)
case FilterOperatorIsGreaterOrEqual:
return valueTime.After(otherValueStart) || valueTime.Equal(otherValueStart)
case FilterOperatorIsLess:
return valueTime.Before(otherValueStart)
case FilterOperatorIsLessOrEqual:
return valueTime.Before(otherValueEnd) || valueTime.Equal(otherValueEnd)
case FilterOperatorIsBetween:
return (valueTime.After(otherValueStart) || valueTime.Equal(otherValueStart)) && (valueTime.Before(otherValueEnd2) || valueTime.Equal(otherValueEnd2))
case FilterOperatorIsEmpty:
return !valueIsNotEmpty
case FilterOperatorIsNotEmpty:
return valueIsNotEmpty
}
return false
}
// 根据 Count、Unit 和 Direction 计算相对当前时间的开始时间和结束时间
func calcRelativeTimeRegion(count int, unit RelativeDateUnit, direction RelativeDateDirection) (start, end time.Time) {
now := time.Now()
switch unit {
case RelativeDateUnitDay:
switch direction {
case RelativeDateDirectionBefore:
// 结束时间使用今天的开始时间
end = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
// 开始时间使用结束时间减去 count 天
start = end.AddDate(0, 0, -count)
case RelativeDateDirectionThis:
// 开始时间使用今天的开始时间
start = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
// 结束时间使用开始时间加上 count 天
end = start.AddDate(0, 0, count)
case RelativeDateDirectionAfter:
// 开始时间使用今天的结束时间
start = time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 999999999, now.Location())
// 结束时间使用开始时间加上 count 天
end = start.AddDate(0, 0, count)
}
case RelativeDateUnitWeek:
weekday := int(now.Weekday())
if 0 == weekday {
weekday = 7
}
switch direction {
case RelativeDateDirectionBefore:
// 结束时间使用本周的开始时间
end = time.Date(now.Year(), now.Month(), now.Day()-weekday, 0, 0, 0, 0, now.Location())
// 开始时间使用结束时间减去 count*7 天
start = end.AddDate(0, 0, -count*7)
case RelativeDateDirectionThis:
// 开始时间使用本周的开始时间
start = time.Date(now.Year(), now.Month(), now.Day()-weekday, 0, 0, 0, 0, now.Location())
// 结束时间使用开始时间加上 count*7 天
end = start.AddDate(0, 0, count*7)
case RelativeDateDirectionAfter:
// 开始时间使用本周的结束时间
start = time.Date(now.Year(), now.Month(), now.Day()-weekday+7, 23, 59, 59, 999999999, now.Location())
// 结束时间使用开始时间加上 count*7 天
end = start.AddDate(0, 0, count*7)
}
case RelativeDateUnitMonth:
switch direction {
case RelativeDateDirectionBefore:
// 结束时间使用本月的开始时间
end = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
// 开始时间使用结束时间减去 count 个月
start = end.AddDate(0, -count, 0)
case RelativeDateDirectionThis:
// 开始时间使用本月的开始时间
start = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
// 结束时间使用开始时间加上 count 个月
end = start.AddDate(0, count, 0)
case RelativeDateDirectionAfter:
// 开始时间使用本月的结束时间
start = time.Date(now.Year(), now.Month()+1, 1, 0, 0, 0, 0, now.Location()).Add(-time.Nanosecond)
// 结束时间使用开始时间加上 count 个月
end = start.AddDate(0, count, 0)
}
case RelativeDateUnitYear:
switch direction {
case RelativeDateDirectionBefore:
// 结束时间使用今年的开始时间
end = time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location())
// 开始时间使用结束时间减去 count 年
start = end.AddDate(-count, 0, 0)
case RelativeDateDirectionThis:
// 开始时间使用今年的开始时间
start = time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location())
// 结束时间使用开始时间加上 count 年
end = start.AddDate(count, 0, 0)
case RelativeDateDirectionAfter:
// 开始时间使用今年的结束时间
start = time.Date(now.Year()+1, 1, 1, 0, 0, 0, 0, now.Location()).Add(-time.Nanosecond)
// 结束时间使用开始时间加上 count 年
end = start.AddDate(count, 0, 0)
}
}
return
}
func (filter *ViewFilter) GetAffectValue(key *Key, defaultVal *Value) (ret *Value) { func (filter *ViewFilter) GetAffectValue(key *Key, defaultVal *Value) (ret *Value) {
if nil != filter.Value { if nil != filter.Value {
if KeyTypeRelation == filter.Value.Type || KeyTypeTemplate == filter.Value.Type || KeyTypeRollup == filter.Value.Type || KeyTypeUpdated == filter.Value.Type || KeyTypeCreated == filter.Value.Type { if KeyTypeRelation == filter.Value.Type || KeyTypeTemplate == filter.Value.Type || KeyTypeRollup == filter.Value.Type || KeyTypeUpdated == filter.Value.Type || KeyTypeCreated == filter.Value.Type {

View file

@ -16,6 +16,14 @@
package av package av
import (
"bytes"
"strconv"
"strings"
"github.com/siyuan-note/siyuan/kernel/util"
)
type Sortable interface { type Sortable interface {
SortRows() SortRows()
} }
@ -31,3 +39,238 @@ const (
SortOrderAsc SortOrder = "ASC" SortOrderAsc SortOrder = "ASC"
SortOrderDesc SortOrder = "DESC" SortOrderDesc SortOrder = "DESC"
) )
func (value *Value) Compare(other *Value) int {
switch value.Type {
case KeyTypeBlock:
if nil != value.Block && nil != other.Block {
ret := strings.Compare(value.Block.Content, other.Block.Content)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeText:
if nil != value.Text && nil != other.Text {
ret := strings.Compare(value.Text.Content, other.Text.Content)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeNumber:
if nil != value.Number && nil != other.Number {
if value.Number.IsNotEmpty {
if !other.Number.IsNotEmpty {
return 1
}
if value.Number.Content > other.Number.Content {
return 1
} else if value.Number.Content < other.Number.Content {
return -1
} else {
return int(value.CreatedAt - other.CreatedAt)
}
} else {
if other.Number.IsNotEmpty {
return -1
}
return int(value.CreatedAt - other.CreatedAt)
}
}
case KeyTypeDate:
if nil != value.Date && nil != other.Date {
if value.Date.IsNotEmpty {
if !other.Date.IsNotEmpty {
return 1
}
if value.Date.Content > other.Date.Content {
return 1
} else if value.Date.Content < other.Date.Content {
return -1
} else {
return int(value.CreatedAt - other.CreatedAt)
}
} else {
if other.Date.IsNotEmpty {
return -1
}
return int(value.CreatedAt - other.CreatedAt)
}
}
case KeyTypeCreated:
if nil != value.Created && nil != other.Created {
if value.Created.Content > other.Created.Content {
return 1
} else if value.Created.Content < other.Created.Content {
return -1
} else {
return int(value.CreatedAt - other.CreatedAt)
}
}
case KeyTypeUpdated:
if nil != value.Updated && nil != other.Updated {
if value.Updated.Content > other.Updated.Content {
return 1
} else if value.Updated.Content < other.Updated.Content {
return -1
} else {
return int(value.CreatedAt - other.CreatedAt)
}
}
case KeyTypeSelect, KeyTypeMSelect:
if nil != value.MSelect && nil != other.MSelect {
var v1 string
for _, v := range value.MSelect {
v1 += v.Content
}
var v2 string
for _, v := range other.MSelect {
v2 += v.Content
}
ret := strings.Compare(v1, v2)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeURL:
if nil != value.URL && nil != other.URL {
ret := strings.Compare(value.URL.Content, other.URL.Content)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeEmail:
if nil != value.Email && nil != other.Email {
ret := strings.Compare(value.Email.Content, other.Email.Content)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypePhone:
if nil != value.Phone && nil != other.Phone {
ret := strings.Compare(value.Phone.Content, other.Phone.Content)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeMAsset:
if nil != value.MAsset && nil != other.MAsset {
var v1 string
for _, v := range value.MAsset {
v1 += v.Content
}
var v2 string
for _, v := range other.MAsset {
v2 += v.Content
}
ret := strings.Compare(v1, v2)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeTemplate:
if nil != value.Template && nil != other.Template {
vContent := strings.TrimSpace(value.Template.Content)
oContent := strings.TrimSpace(other.Template.Content)
if util.IsNumeric(vContent) && util.IsNumeric(oContent) {
v1, _ := strconv.ParseFloat(vContent, 64)
v2, _ := strconv.ParseFloat(oContent, 64)
if v1 > v2 {
return 1
}
if v1 < v2 {
return -1
}
return int(value.CreatedAt - other.CreatedAt)
}
ret := strings.Compare(value.Template.Content, other.Template.Content)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeCheckbox:
if nil != value.Checkbox && nil != other.Checkbox {
if value.Checkbox.Checked && !other.Checkbox.Checked {
return 1
}
if !value.Checkbox.Checked && other.Checkbox.Checked {
return -1
}
return int(value.CreatedAt - other.CreatedAt)
}
case KeyTypeRelation:
if nil != value.Relation && nil != other.Relation {
vContentBuf := bytes.Buffer{}
for _, c := range value.Relation.Contents {
vContentBuf.WriteString(c.String())
vContentBuf.WriteByte(' ')
}
vContent := strings.TrimSpace(vContentBuf.String())
oContentBuf := bytes.Buffer{}
for _, c := range other.Relation.Contents {
oContentBuf.WriteString(c.String())
oContentBuf.WriteByte(' ')
}
oContent := strings.TrimSpace(oContentBuf.String())
if util.IsNumeric(vContent) && util.IsNumeric(oContent) {
v1, _ := strconv.ParseFloat(vContent, 64)
v2, _ := strconv.ParseFloat(oContent, 64)
if v1 > v2 {
return 1
}
if v1 < v2 {
return -1
}
return int(value.CreatedAt - other.CreatedAt)
}
ret := strings.Compare(vContent, oContent)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeRollup:
if nil != value.Rollup && nil != other.Rollup {
vContentBuf := bytes.Buffer{}
for _, c := range value.Rollup.Contents {
vContentBuf.WriteString(c.String())
vContentBuf.WriteByte(' ')
}
vContent := strings.TrimSpace(vContentBuf.String())
oContentBuf := bytes.Buffer{}
for _, c := range other.Rollup.Contents {
oContentBuf.WriteString(c.String())
oContentBuf.WriteByte(' ')
}
oContent := strings.TrimSpace(oContentBuf.String())
if util.IsNumeric(vContent) && util.IsNumeric(oContent) {
v1, _ := strconv.ParseFloat(vContent, 64)
v2, _ := strconv.ParseFloat(oContent, 64)
if v1 > v2 {
return 1
}
if v1 < v2 {
return -1
}
return int(value.CreatedAt - other.CreatedAt)
}
ret := strings.Compare(vContent, oContent)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
}
return int(value.CreatedAt - other.CreatedAt)
}

View file

@ -17,13 +17,9 @@
package av package av
import ( import (
"bytes"
"github.com/siyuan-note/siyuan/kernel/util"
"math" "math"
"sort" "sort"
"strconv" "strconv"
"strings"
"time"
) )
// LayoutTable 描述了表格布局的结构。 // LayoutTable 描述了表格布局的结构。
@ -82,775 +78,6 @@ const (
CalcOperatorPercentUnchecked CalcOperator = "Percent unchecked" CalcOperatorPercentUnchecked CalcOperator = "Percent unchecked"
) )
func (value *Value) Compare(other *Value) int {
switch value.Type {
case KeyTypeBlock:
if nil != value.Block && nil != other.Block {
ret := strings.Compare(value.Block.Content, other.Block.Content)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeText:
if nil != value.Text && nil != other.Text {
ret := strings.Compare(value.Text.Content, other.Text.Content)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeNumber:
if nil != value.Number && nil != other.Number {
if value.Number.IsNotEmpty {
if !other.Number.IsNotEmpty {
return 1
}
if value.Number.Content > other.Number.Content {
return 1
} else if value.Number.Content < other.Number.Content {
return -1
} else {
return int(value.CreatedAt - other.CreatedAt)
}
} else {
if other.Number.IsNotEmpty {
return -1
}
return int(value.CreatedAt - other.CreatedAt)
}
}
case KeyTypeDate:
if nil != value.Date && nil != other.Date {
if value.Date.IsNotEmpty {
if !other.Date.IsNotEmpty {
return 1
}
if value.Date.Content > other.Date.Content {
return 1
} else if value.Date.Content < other.Date.Content {
return -1
} else {
return int(value.CreatedAt - other.CreatedAt)
}
} else {
if other.Date.IsNotEmpty {
return -1
}
return int(value.CreatedAt - other.CreatedAt)
}
}
case KeyTypeCreated:
if nil != value.Created && nil != other.Created {
if value.Created.Content > other.Created.Content {
return 1
} else if value.Created.Content < other.Created.Content {
return -1
} else {
return int(value.CreatedAt - other.CreatedAt)
}
}
case KeyTypeUpdated:
if nil != value.Updated && nil != other.Updated {
if value.Updated.Content > other.Updated.Content {
return 1
} else if value.Updated.Content < other.Updated.Content {
return -1
} else {
return int(value.CreatedAt - other.CreatedAt)
}
}
case KeyTypeSelect, KeyTypeMSelect:
if nil != value.MSelect && nil != other.MSelect {
var v1 string
for _, v := range value.MSelect {
v1 += v.Content
}
var v2 string
for _, v := range other.MSelect {
v2 += v.Content
}
ret := strings.Compare(v1, v2)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeURL:
if nil != value.URL && nil != other.URL {
ret := strings.Compare(value.URL.Content, other.URL.Content)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeEmail:
if nil != value.Email && nil != other.Email {
ret := strings.Compare(value.Email.Content, other.Email.Content)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypePhone:
if nil != value.Phone && nil != other.Phone {
ret := strings.Compare(value.Phone.Content, other.Phone.Content)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeMAsset:
if nil != value.MAsset && nil != other.MAsset {
var v1 string
for _, v := range value.MAsset {
v1 += v.Content
}
var v2 string
for _, v := range other.MAsset {
v2 += v.Content
}
ret := strings.Compare(v1, v2)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeTemplate:
if nil != value.Template && nil != other.Template {
vContent := strings.TrimSpace(value.Template.Content)
oContent := strings.TrimSpace(other.Template.Content)
if util.IsNumeric(vContent) && util.IsNumeric(oContent) {
v1, _ := strconv.ParseFloat(vContent, 64)
v2, _ := strconv.ParseFloat(oContent, 64)
if v1 > v2 {
return 1
}
if v1 < v2 {
return -1
}
return int(value.CreatedAt - other.CreatedAt)
}
ret := strings.Compare(value.Template.Content, other.Template.Content)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeCheckbox:
if nil != value.Checkbox && nil != other.Checkbox {
if value.Checkbox.Checked && !other.Checkbox.Checked {
return 1
}
if !value.Checkbox.Checked && other.Checkbox.Checked {
return -1
}
return int(value.CreatedAt - other.CreatedAt)
}
case KeyTypeRelation:
if nil != value.Relation && nil != other.Relation {
vContentBuf := bytes.Buffer{}
for _, c := range value.Relation.Contents {
vContentBuf.WriteString(c.String())
vContentBuf.WriteByte(' ')
}
vContent := strings.TrimSpace(vContentBuf.String())
oContentBuf := bytes.Buffer{}
for _, c := range other.Relation.Contents {
oContentBuf.WriteString(c.String())
oContentBuf.WriteByte(' ')
}
oContent := strings.TrimSpace(oContentBuf.String())
if util.IsNumeric(vContent) && util.IsNumeric(oContent) {
v1, _ := strconv.ParseFloat(vContent, 64)
v2, _ := strconv.ParseFloat(oContent, 64)
if v1 > v2 {
return 1
}
if v1 < v2 {
return -1
}
return int(value.CreatedAt - other.CreatedAt)
}
ret := strings.Compare(vContent, oContent)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
case KeyTypeRollup:
if nil != value.Rollup && nil != other.Rollup {
vContentBuf := bytes.Buffer{}
for _, c := range value.Rollup.Contents {
vContentBuf.WriteString(c.String())
vContentBuf.WriteByte(' ')
}
vContent := strings.TrimSpace(vContentBuf.String())
oContentBuf := bytes.Buffer{}
for _, c := range other.Rollup.Contents {
oContentBuf.WriteString(c.String())
oContentBuf.WriteByte(' ')
}
oContent := strings.TrimSpace(oContentBuf.String())
if util.IsNumeric(vContent) && util.IsNumeric(oContent) {
v1, _ := strconv.ParseFloat(vContent, 64)
v2, _ := strconv.ParseFloat(oContent, 64)
if v1 > v2 {
return 1
}
if v1 < v2 {
return -1
}
return int(value.CreatedAt - other.CreatedAt)
}
ret := strings.Compare(vContent, oContent)
if 0 == ret {
ret = int(value.CreatedAt - other.CreatedAt)
}
return ret
}
}
return int(value.CreatedAt - other.CreatedAt)
}
func (value *Value) Filter(filter *ViewFilter, attrView *AttributeView, rowID string) bool {
if nil == filter || (nil == filter.Value && nil == filter.RelativeDate) {
return true
}
if nil != filter.Value && value.Type != filter.Value.Type {
// 由于字段类型被用户编辑过导致和过滤器值类型不匹配,该情况下不过滤
return true
}
if nil != value.Rollup && KeyTypeRollup == value.Type && nil != filter && nil != filter.Value && KeyTypeRollup == filter.Value.Type &&
nil != filter.Value.Rollup && 0 < len(filter.Value.Rollup.Contents) {
// 单独处理汇总类型的比较
key, _ := attrView.GetKey(value.KeyID)
if nil == key {
return false
}
relKey, _ := attrView.GetKey(key.Rollup.RelationKeyID)
if nil == relKey {
return false
}
relVal := attrView.GetValue(relKey.ID, rowID)
if nil == relVal || nil == relVal.Relation {
return false
}
destAv, _ := ParseAttributeView(relKey.Relation.AvID)
if nil == destAv {
return false
}
for _, blockID := range relVal.Relation.BlockIDs {
destVal := destAv.GetValue(key.Rollup.KeyID, blockID)
if nil == destVal {
continue
}
if destVal.filter(filter.Value.Rollup.Contents[0], filter.RelativeDate, filter.RelativeDate2, filter.Operator) {
return true
}
}
return false
}
if nil != value.Relation && KeyTypeRelation == value.Type && 0 < len(value.Relation.Contents) && nil != filter && nil != filter.Value && KeyTypeRelation == filter.Value.Type &&
nil != filter.Value.Relation && 0 < len(filter.Value.Relation.BlockIDs) {
// 单独处理关联类型的比较
for _, relationValue := range value.Relation.Contents {
filterValue := &Value{Type: KeyTypeBlock, Block: &ValueBlock{Content: filter.Value.Relation.BlockIDs[0]}}
if relationValue.filter(filterValue, filter.RelativeDate, filter.RelativeDate2, filter.Operator) {
return true
}
}
return false
}
return value.filter(filter.Value, filter.RelativeDate, filter.RelativeDate2, filter.Operator)
}
func (value *Value) filter(other *Value, relativeDate, relativeDate2 *RelativeDate, operator FilterOperator) bool {
switch value.Type {
case KeyTypeBlock:
if nil != value.Block && nil != other && nil != other.Block {
switch operator {
case FilterOperatorIsEqual:
return value.Block.Content == other.Block.Content
case FilterOperatorIsNotEqual:
return value.Block.Content != other.Block.Content
case FilterOperatorContains:
return strings.Contains(value.Block.Content, other.Block.Content)
case FilterOperatorDoesNotContain:
return !strings.Contains(value.Block.Content, other.Block.Content)
case FilterOperatorStartsWith:
return strings.HasPrefix(value.Block.Content, other.Block.Content)
case FilterOperatorEndsWith:
return strings.HasSuffix(value.Block.Content, other.Block.Content)
case FilterOperatorIsEmpty:
return "" == strings.TrimSpace(value.Block.Content)
case FilterOperatorIsNotEmpty:
return "" != strings.TrimSpace(value.Block.Content)
}
}
case KeyTypeText:
if nil != value.Text && nil != other && nil != other.Text {
switch operator {
case FilterOperatorIsEqual:
if "" == strings.TrimSpace(other.Text.Content) {
return true
}
return value.Text.Content == other.Text.Content
case FilterOperatorIsNotEqual:
if "" == strings.TrimSpace(other.Text.Content) {
return true
}
return value.Text.Content != other.Text.Content
case FilterOperatorContains:
if "" == strings.TrimSpace(other.Text.Content) {
return true
}
return strings.Contains(value.Text.Content, other.Text.Content)
case FilterOperatorDoesNotContain:
if "" == strings.TrimSpace(other.Text.Content) {
return true
}
return !strings.Contains(value.Text.Content, other.Text.Content)
case FilterOperatorStartsWith:
if "" == strings.TrimSpace(other.Text.Content) {
return true
}
return strings.HasPrefix(value.Text.Content, other.Text.Content)
case FilterOperatorEndsWith:
if "" == strings.TrimSpace(other.Text.Content) {
return true
}
return strings.HasSuffix(value.Text.Content, other.Text.Content)
case FilterOperatorIsEmpty:
return "" == strings.TrimSpace(value.Text.Content)
case FilterOperatorIsNotEmpty:
return "" != strings.TrimSpace(value.Text.Content)
}
}
case KeyTypeNumber:
if nil != value.Number && nil != other && nil != other.Number {
switch operator {
case FilterOperatorIsEqual:
if !other.Number.IsNotEmpty {
return true
}
return value.Number.Content == other.Number.Content
case FilterOperatorIsNotEqual:
if !other.Number.IsNotEmpty {
return true
}
return value.Number.Content != other.Number.Content
case FilterOperatorIsGreater:
return value.Number.Content > other.Number.Content
case FilterOperatorIsGreaterOrEqual:
return value.Number.Content >= other.Number.Content
case FilterOperatorIsLess:
return value.Number.Content < other.Number.Content
case FilterOperatorIsLessOrEqual:
return value.Number.Content <= other.Number.Content
case FilterOperatorIsEmpty:
return !value.Number.IsNotEmpty
case FilterOperatorIsNotEmpty:
return value.Number.IsNotEmpty
}
}
case KeyTypeDate:
if nil != value.Date {
if nil != relativeDate {
// 使用相对时间比较
count := relativeDate.Count
unit := relativeDate.Unit
direction := relativeDate.Direction
relativeTimeStart, relativeTimeEnd := calcRelativeTimeRegion(count, unit, direction)
_, relativeTimeEnd2 := calcRelativeTimeRegion(relativeDate2.Count, relativeDate2.Unit, relativeDate2.Direction)
return filterTime(value.Date.Content, value.Date.IsNotEmpty, relativeTimeStart, relativeTimeEnd, relativeTimeEnd2, operator)
} else { // 使用具体时间比较
if nil == other.Date {
return true
}
otherTime := time.UnixMilli(other.Date.Content)
otherStart := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 0, 0, 0, 0, otherTime.Location())
otherEnd := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 23, 59, 59, 999999999, otherTime.Location())
return filterTime(value.Date.Content, value.Date.IsNotEmpty, otherStart, otherEnd, time.Now(), operator)
}
}
case KeyTypeCreated:
if nil != value.Created {
if nil != relativeDate {
// 使用相对时间比较
count := relativeDate.Count
unit := relativeDate.Unit
direction := relativeDate.Direction
relativeTimeStart, relativeTimeEnd := calcRelativeTimeRegion(count, unit, direction)
return filterTime(value.Created.Content, true, relativeTimeStart, relativeTimeEnd, time.Now(), operator)
} else { // 使用具体时间比较
if nil == other.Created {
return true
}
otherTime := time.UnixMilli(other.Created.Content)
otherStart := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 0, 0, 0, 0, otherTime.Location())
otherEnd := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 23, 59, 59, 999999999, otherTime.Location())
return filterTime(value.Created.Content, value.Created.IsNotEmpty, otherStart, otherEnd, time.Now(), operator)
}
}
case KeyTypeUpdated:
if nil != value.Updated {
if nil != relativeDate {
// 使用相对时间比较
count := relativeDate.Count
unit := relativeDate.Unit
direction := relativeDate.Direction
relativeTimeStart, relativeTimeEnd := calcRelativeTimeRegion(count, unit, direction)
return filterTime(value.Updated.Content, true, relativeTimeStart, relativeTimeEnd, time.Now(), operator)
} else { // 使用具体时间比较
if nil == other.Updated {
return true
}
otherTime := time.UnixMilli(other.Updated.Content)
otherStart := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 0, 0, 0, 0, otherTime.Location())
otherEnd := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 23, 59, 59, 999999999, otherTime.Location())
return filterTime(value.Updated.Content, value.Updated.IsNotEmpty, otherStart, otherEnd, time.Now(), operator)
}
}
case KeyTypeSelect, KeyTypeMSelect:
if nil != value.MSelect {
if nil != other && nil != other.MSelect {
switch operator {
case FilterOperatorIsEqual, FilterOperatorContains:
contains := false
for _, v := range value.MSelect {
for _, v2 := range other.MSelect {
if v.Content == v2.Content {
contains = true
break
}
}
}
return contains
case FilterOperatorIsNotEqual, FilterOperatorDoesNotContain:
contains := false
for _, v := range value.MSelect {
for _, v2 := range other.MSelect {
if v.Content == v2.Content {
contains = true
break
}
}
}
return !contains
case FilterOperatorIsEmpty:
return 0 == len(value.MSelect) || 1 == len(value.MSelect) && "" == value.MSelect[0].Content
case FilterOperatorIsNotEmpty:
return 0 != len(value.MSelect) && !(1 == len(value.MSelect) && "" == value.MSelect[0].Content)
}
return false
}
// 没有设置比较值
switch operator {
case FilterOperatorIsEqual, FilterOperatorIsNotEqual, FilterOperatorContains, FilterOperatorDoesNotContain:
return true
case FilterOperatorIsEmpty:
return 0 == len(value.MSelect) || 1 == len(value.MSelect) && "" == value.MSelect[0].Content
case FilterOperatorIsNotEmpty:
return 0 != len(value.MSelect) && !(1 == len(value.MSelect) && "" == value.MSelect[0].Content)
}
}
case KeyTypeURL:
if nil != value.URL && nil != other && nil != other.URL {
switch operator {
case FilterOperatorIsEqual:
return value.URL.Content == other.URL.Content
case FilterOperatorIsNotEqual:
return value.URL.Content != other.URL.Content
case FilterOperatorContains:
return strings.Contains(value.URL.Content, other.URL.Content)
case FilterOperatorDoesNotContain:
return !strings.Contains(value.URL.Content, other.URL.Content)
case FilterOperatorStartsWith:
return strings.HasPrefix(value.URL.Content, other.URL.Content)
case FilterOperatorEndsWith:
return strings.HasSuffix(value.URL.Content, other.URL.Content)
case FilterOperatorIsEmpty:
return "" == strings.TrimSpace(value.URL.Content)
case FilterOperatorIsNotEmpty:
return "" != strings.TrimSpace(value.URL.Content)
}
}
case KeyTypeEmail:
if nil != value.Email && nil != other && nil != other.Email {
switch operator {
case FilterOperatorIsEqual:
return value.Email.Content == other.Email.Content
case FilterOperatorIsNotEqual:
return value.Email.Content != other.Email.Content
case FilterOperatorContains:
return strings.Contains(value.Email.Content, other.Email.Content)
case FilterOperatorDoesNotContain:
return !strings.Contains(value.Email.Content, other.Email.Content)
case FilterOperatorStartsWith:
return strings.HasPrefix(value.Email.Content, other.Email.Content)
case FilterOperatorEndsWith:
return strings.HasSuffix(value.Email.Content, other.Email.Content)
case FilterOperatorIsEmpty:
return "" == strings.TrimSpace(value.Email.Content)
case FilterOperatorIsNotEmpty:
return "" != strings.TrimSpace(value.Email.Content)
}
}
case KeyTypePhone:
if nil != value.Phone && nil != other && nil != other.Phone {
switch operator {
case FilterOperatorIsEqual:
return value.Phone.Content == other.Phone.Content
case FilterOperatorIsNotEqual:
return value.Phone.Content != other.Phone.Content
case FilterOperatorContains:
return strings.Contains(value.Phone.Content, other.Phone.Content)
case FilterOperatorDoesNotContain:
return !strings.Contains(value.Phone.Content, other.Phone.Content)
case FilterOperatorStartsWith:
return strings.HasPrefix(value.Phone.Content, other.Phone.Content)
case FilterOperatorEndsWith:
return strings.HasSuffix(value.Phone.Content, other.Phone.Content)
case FilterOperatorIsEmpty:
return "" == strings.TrimSpace(value.Phone.Content)
case FilterOperatorIsNotEmpty:
return "" != strings.TrimSpace(value.Phone.Content)
}
}
case KeyTypeMAsset:
if nil != value.MAsset && nil != other && nil != other.MAsset && 0 < len(value.MAsset) && 0 < len(other.MAsset) {
switch operator {
case FilterOperatorIsEqual, FilterOperatorContains:
contains := false
for _, v := range value.MAsset {
for _, v2 := range other.MAsset {
if v.Content == v2.Content {
contains = true
break
}
}
}
return contains
case FilterOperatorIsNotEqual, FilterOperatorDoesNotContain:
contains := false
for _, v := range value.MAsset {
for _, v2 := range other.MAsset {
if v.Content == v2.Content {
contains = true
break
}
}
}
return !contains
case FilterOperatorIsEmpty:
return 0 == len(value.MAsset) || 1 == len(value.MAsset) && "" == value.MAsset[0].Content
case FilterOperatorIsNotEmpty:
return 0 != len(value.MAsset) && !(1 == len(value.MAsset) && "" == value.MAsset[0].Content)
}
}
case KeyTypeTemplate:
if nil != value.Template && nil != other && nil != other.Template {
switch operator {
case FilterOperatorIsEqual:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return value.Template.Content == other.Template.Content
case FilterOperatorIsNotEqual:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return value.Template.Content != other.Template.Content
case FilterOperatorIsGreater:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return value.Template.Content > other.Template.Content
case FilterOperatorIsGreaterOrEqual:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return value.Template.Content >= other.Template.Content
case FilterOperatorIsLess:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return value.Template.Content < other.Template.Content
case FilterOperatorIsLessOrEqual:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return value.Template.Content <= other.Template.Content
case FilterOperatorContains:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return strings.Contains(value.Template.Content, other.Template.Content)
case FilterOperatorDoesNotContain:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return !strings.Contains(value.Template.Content, other.Template.Content)
case FilterOperatorStartsWith:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return strings.HasPrefix(value.Template.Content, other.Template.Content)
case FilterOperatorEndsWith:
if "" == strings.TrimSpace(other.Template.Content) {
return true
}
return strings.HasSuffix(value.Template.Content, other.Template.Content)
case FilterOperatorIsEmpty:
return "" == strings.TrimSpace(value.Template.Content)
case FilterOperatorIsNotEmpty:
return "" != strings.TrimSpace(value.Template.Content)
}
}
case KeyTypeCheckbox:
if nil != value.Checkbox {
switch operator {
case FilterOperatorIsTrue:
return value.Checkbox.Checked
case FilterOperatorIsFalse:
return !value.Checkbox.Checked
}
}
}
return false
}
func filterTime(valueMills int64, valueIsNotEmpty bool, otherValueStart, otherValueEnd, otherValueEnd2 time.Time, operator FilterOperator) bool {
valueTime := time.UnixMilli(valueMills)
switch operator {
case FilterOperatorIsEqual:
return (valueTime.After(otherValueStart) || valueTime.Equal(otherValueStart)) && valueTime.Before(otherValueEnd)
case FilterOperatorIsNotEqual:
return valueTime.Before(otherValueStart) || valueTime.After(otherValueEnd)
case FilterOperatorIsGreater:
return valueTime.After(otherValueEnd) || valueTime.Equal(otherValueEnd)
case FilterOperatorIsGreaterOrEqual:
return valueTime.After(otherValueStart) || valueTime.Equal(otherValueStart)
case FilterOperatorIsLess:
return valueTime.Before(otherValueStart)
case FilterOperatorIsLessOrEqual:
return valueTime.Before(otherValueEnd) || valueTime.Equal(otherValueEnd)
case FilterOperatorIsBetween:
return (valueTime.After(otherValueStart) || valueTime.Equal(otherValueStart)) && (valueTime.Before(otherValueEnd2) || valueTime.Equal(otherValueEnd2))
case FilterOperatorIsEmpty:
return !valueIsNotEmpty
case FilterOperatorIsNotEmpty:
return valueIsNotEmpty
}
return false
}
// 根据 Count、Unit 和 Direction 计算相对当前时间的开始时间和结束时间
func calcRelativeTimeRegion(count int, unit RelativeDateUnit, direction RelativeDateDirection) (start, end time.Time) {
now := time.Now()
switch unit {
case RelativeDateUnitDay:
switch direction {
case RelativeDateDirectionBefore:
// 结束时间使用今天的开始时间
end = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
// 开始时间使用结束时间减去 count 天
start = end.AddDate(0, 0, -count)
case RelativeDateDirectionThis:
// 开始时间使用今天的开始时间
start = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
// 结束时间使用开始时间加上 count 天
end = start.AddDate(0, 0, count)
case RelativeDateDirectionAfter:
// 开始时间使用今天的结束时间
start = time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 999999999, now.Location())
// 结束时间使用开始时间加上 count 天
end = start.AddDate(0, 0, count)
}
case RelativeDateUnitWeek:
weekday := int(now.Weekday())
if 0 == weekday {
weekday = 7
}
switch direction {
case RelativeDateDirectionBefore:
// 结束时间使用本周的开始时间
end = time.Date(now.Year(), now.Month(), now.Day()-weekday, 0, 0, 0, 0, now.Location())
// 开始时间使用结束时间减去 count*7 天
start = end.AddDate(0, 0, -count*7)
case RelativeDateDirectionThis:
// 开始时间使用本周的开始时间
start = time.Date(now.Year(), now.Month(), now.Day()-weekday, 0, 0, 0, 0, now.Location())
// 结束时间使用开始时间加上 count*7 天
end = start.AddDate(0, 0, count*7)
case RelativeDateDirectionAfter:
// 开始时间使用本周的结束时间
start = time.Date(now.Year(), now.Month(), now.Day()-weekday+7, 23, 59, 59, 999999999, now.Location())
// 结束时间使用开始时间加上 count*7 天
end = start.AddDate(0, 0, count*7)
}
case RelativeDateUnitMonth:
switch direction {
case RelativeDateDirectionBefore:
// 结束时间使用本月的开始时间
end = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
// 开始时间使用结束时间减去 count 个月
start = end.AddDate(0, -count, 0)
case RelativeDateDirectionThis:
// 开始时间使用本月的开始时间
start = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
// 结束时间使用开始时间加上 count 个月
end = start.AddDate(0, count, 0)
case RelativeDateDirectionAfter:
// 开始时间使用本月的结束时间
start = time.Date(now.Year(), now.Month()+1, 1, 0, 0, 0, 0, now.Location()).Add(-time.Nanosecond)
// 结束时间使用开始时间加上 count 个月
end = start.AddDate(0, count, 0)
}
case RelativeDateUnitYear:
switch direction {
case RelativeDateDirectionBefore:
// 结束时间使用今年的开始时间
end = time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location())
// 开始时间使用结束时间减去 count 年
start = end.AddDate(-count, 0, 0)
case RelativeDateDirectionThis:
// 开始时间使用今年的开始时间
start = time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location())
// 结束时间使用开始时间加上 count 年
end = start.AddDate(count, 0, 0)
case RelativeDateDirectionAfter:
// 开始时间使用今年的结束时间
start = time.Date(now.Year()+1, 1, 1, 0, 0, 0, 0, now.Location()).Add(-time.Nanosecond)
// 结束时间使用开始时间加上 count 年
end = start.AddDate(count, 0, 0)
}
}
return
}
// Table 描述了表格实例的结构。 // Table 描述了表格实例的结构。
type Table struct { type Table struct {
ID string `json:"id"` // 表格布局 ID ID string `json:"id"` // 表格布局 ID