mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-17 23:20:13 +01:00
🐛 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:
parent
cc9aed6aec
commit
e02e4daa1c
3 changed files with 797 additions and 773 deletions
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue