mirror of
https://github.com/anyproto/anytype-heart.git
synced 2025-06-08 05:47:07 +09:00
GO-4144 Merge branch 'main' of github.com:anyproto/anytype-heart into go-4144-refactor-internal-details-structure
# Conflicts: # core/block/backlinks/watcher.go # core/block/bookmark/bookmarkimporter/bookmark_importer_decorator.go # core/block/detailservice/mock_detailservice/mock_Service.go # core/block/detailservice/relations.go # core/block/detailservice/relations_test.go # core/block/detailservice/service.go # core/block/detailservice/set_details.go # core/block/editor/collection/collection.go # core/block/editor/dashboard.go # core/block/import/importer.go # core/block/import/importer_test.go # core/block/import/types.go # core/block/object/objectcreator/creator_test.go # core/block/object/objectlink/dependent_objects.go # core/block/source/date.go # core/object.go # core/relations.go # pkg/lib/database/database.go # pkg/lib/database/filter.go # pkg/lib/database/filter_test.go # pkg/lib/localstore/objectstore/spaceindex/queries.go # pkg/lib/localstore/objectstore/spaceindex/queries_test.go
This commit is contained in:
commit
e34cef28ca
121 changed files with 7814 additions and 5186 deletions
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/anyproto/anytype-heart/core/domain"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/localstore/ftsearch"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/logging"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
|
||||
)
|
||||
|
@ -66,10 +65,9 @@ type SortRequest struct {
|
|||
}
|
||||
|
||||
type Query struct {
|
||||
FullText string
|
||||
SpaceId string
|
||||
Highlighter ftsearch.HighlightFormatter // default is json
|
||||
Filters []FilterRequest // filters results. apply sequentially
|
||||
TextQuery string
|
||||
SpaceId string
|
||||
Filters []FilterRequest // filters results. apply sequentially
|
||||
Sorts []SortRequest // order results. apply hierarchically
|
||||
Limit int // maximum number of results
|
||||
Offset int // skip given number of results
|
||||
|
@ -159,7 +157,7 @@ func injectDefaultOrder(qry Query, sorts []SortRequest) []SortRequest {
|
|||
var (
|
||||
hasScoreSort bool
|
||||
)
|
||||
if qry.FullText == "" {
|
||||
if qry.TextQuery == "" {
|
||||
return sorts
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,9 @@ import (
|
|||
"github.com/anyproto/anytype-heart/core/domain"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
|
||||
"github.com/anyproto/anytype-heart/util/dateutil"
|
||||
"github.com/anyproto/anytype-heart/util/pbtypes"
|
||||
"github.com/anyproto/anytype-heart/util/slice"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -153,6 +156,14 @@ func makeFilterByCondition(spaceID string, rawFilter FilterRequest, store Object
|
|||
Value: rawFilter.Value.String(),
|
||||
}}, nil
|
||||
case model.BlockContentDataviewFilter_In:
|
||||
// hack for queries for relations containing date objects ids with format _date_YYYY-MM-DD-hh-mm-ss
|
||||
// to find all date object ids of the same day we search by prefix _date_YYYY-MM-DD
|
||||
if ts, err := dateutil.ParseDateId(rawFilter.Value.GetStringValue()); err == nil {
|
||||
return FilterHasPrefix{
|
||||
Key: rawFilter.RelationKey,
|
||||
Prefix: dateutil.TimeToDateId(ts),
|
||||
}, nil
|
||||
}
|
||||
list, err := rawFilter.Value.TryWrapToList()
|
||||
if err != nil {
|
||||
return nil, errors.Join(ErrValueMustBeListSupporting, err)
|
||||
|
@ -456,6 +467,40 @@ func (e FilterEq) filterObject(v domain.Value) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
type FilterHasPrefix struct {
|
||||
Key, Prefix string
|
||||
}
|
||||
|
||||
func (p FilterHasPrefix) FilterObject(s *types.Struct) bool {
|
||||
val := pbtypes.Get(s, p.Key)
|
||||
if strings.HasPrefix(val.GetStringValue(), p.Prefix) {
|
||||
return true
|
||||
}
|
||||
|
||||
list := val.GetListValue()
|
||||
if list == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, v := range list.Values {
|
||||
if strings.HasPrefix(v.GetStringValue(), p.Prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p FilterHasPrefix) AnystoreFilter() query.Filter {
|
||||
re, err := regexp.Compile("^" + regexp.QuoteMeta(p.Prefix))
|
||||
if err != nil {
|
||||
log.Errorf("failed to build anystore HAS PREFIX filter: %v", err)
|
||||
}
|
||||
return query.Key{
|
||||
Path: []string{p.Key},
|
||||
Filter: query.Regexp{Regexp: re},
|
||||
}
|
||||
}
|
||||
|
||||
// any
|
||||
type FilterIn struct {
|
||||
Key domain.RelationKey
|
||||
|
@ -536,14 +581,7 @@ func (e FilterEmpty) FilterObject(g *domain.Details) bool {
|
|||
}
|
||||
|
||||
var (
|
||||
filterEqNil = query.NewComp(query.CompOpEq, nil)
|
||||
filterEqEmptyString = query.NewComp(query.CompOpEq, "")
|
||||
filterEq0 = query.NewComp(query.CompOpEq, 0)
|
||||
filterEqFalse = query.NewComp(query.CompOpEq, false)
|
||||
filterEqEmptyArray = &query.Comp{
|
||||
CompOp: query.CompOpEq,
|
||||
EqValue: anyenc.MustParseJson(`[]`).MarshalTo(nil),
|
||||
}
|
||||
emptyArrayValue = anyenc.MustParseJson(`[]`).MarshalTo(nil)
|
||||
)
|
||||
|
||||
func (e FilterEmpty) AnystoreFilter() query.Filter {
|
||||
|
@ -555,23 +593,26 @@ func (e FilterEmpty) AnystoreFilter() query.Filter {
|
|||
},
|
||||
query.Key{
|
||||
Path: path,
|
||||
Filter: filterEqNil,
|
||||
Filter: query.NewComp(query.CompOpEq, nil),
|
||||
},
|
||||
query.Key{
|
||||
Path: path,
|
||||
Filter: filterEqEmptyString,
|
||||
Filter: query.NewComp(query.CompOpEq, ""),
|
||||
},
|
||||
query.Key{
|
||||
Path: path,
|
||||
Filter: filterEq0,
|
||||
Filter: query.NewComp(query.CompOpEq, 0),
|
||||
},
|
||||
query.Key{
|
||||
Path: path,
|
||||
Filter: filterEqFalse,
|
||||
Filter: query.NewComp(query.CompOpEq, false),
|
||||
},
|
||||
query.Key{
|
||||
Path: path,
|
||||
Filter: filterEqEmptyArray,
|
||||
Path: path,
|
||||
Filter: &query.Comp{
|
||||
CompOp: query.CompOpEq,
|
||||
EqValue: emptyArrayValue,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import (
|
|||
"github.com/anyproto/anytype-heart/core/domain"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
|
||||
"github.com/anyproto/anytype-heart/util/dateutil"
|
||||
"github.com/anyproto/anytype-heart/util/pbtypes"
|
||||
)
|
||||
|
||||
func assertFilter(t *testing.T, f Filter, obj *domain.Details, expected bool) {
|
||||
|
@ -919,3 +921,66 @@ func TestFilter2ValuesComp_FilterObject(t *testing.T) {
|
|||
assertFilter(t, eq, obj3, true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestFilterHasPrefix_FilterObject(t *testing.T) {
|
||||
t.Run("date object id", func(t *testing.T) {
|
||||
key := bundle.RelationKeyMentions.String()
|
||||
now := time.Now()
|
||||
f := FilterHasPrefix{
|
||||
Key: key,
|
||||
Prefix: dateutil.TimeToDateId(now), // _date_YYYY-MM-DD
|
||||
}
|
||||
obj1 := &types.Struct{Fields: map[string]*types.Value{
|
||||
key: pbtypes.StringList([]string{"obj2", dateutil.TimeToDateId(now.Add(30 * time.Minute)), "obj3"}), // _date_YYYY-MM-DD-hh-mm-ss
|
||||
}}
|
||||
obj2 := &types.Struct{Fields: map[string]*types.Value{
|
||||
key: pbtypes.StringList([]string{dateutil.TimeToDateId(now.Add(24 * time.Hour)), "obj1", "obj3"}), // same format, but next day
|
||||
}}
|
||||
obj3 := &types.Struct{Fields: map[string]*types.Value{
|
||||
key: pbtypes.StringList([]string{"obj2", "obj3", dateutil.TimeToDateId(now.Add(30 * time.Minute))}), // _date_YYYY-MM-DD
|
||||
}}
|
||||
assertFilter(t, f, obj1, true)
|
||||
assertFilter(t, f, obj2, false)
|
||||
assertFilter(t, f, obj3, true)
|
||||
})
|
||||
|
||||
t.Run("string", func(t *testing.T) {
|
||||
key := bundle.RelationKeyName.String()
|
||||
f := FilterHasPrefix{
|
||||
Key: key,
|
||||
Prefix: "Let's",
|
||||
}
|
||||
obj1 := &types.Struct{Fields: map[string]*types.Value{
|
||||
key: pbtypes.String("Let's do it"),
|
||||
}}
|
||||
obj2 := &types.Struct{Fields: map[string]*types.Value{
|
||||
key: pbtypes.String("Lets do it"),
|
||||
}}
|
||||
obj3 := &types.Struct{Fields: map[string]*types.Value{
|
||||
key: pbtypes.String("Let's fix it :("),
|
||||
}}
|
||||
assertFilter(t, f, obj1, true)
|
||||
assertFilter(t, f, obj2, false)
|
||||
assertFilter(t, f, obj3, true)
|
||||
})
|
||||
|
||||
t.Run("string list", func(t *testing.T) {
|
||||
toys := "my favorite toys"
|
||||
f := FilterHasPrefix{
|
||||
Key: toys,
|
||||
Prefix: "Fluffy",
|
||||
}
|
||||
obj1 := &types.Struct{Fields: map[string]*types.Value{
|
||||
toys: pbtypes.StringList([]string{"Teddy bear", "Fluffy giraffe"}),
|
||||
}}
|
||||
obj2 := &types.Struct{Fields: map[string]*types.Value{
|
||||
toys: pbtypes.StringList([]string{"Barbie doll", "Peppa Pig"}),
|
||||
}}
|
||||
obj3 := &types.Struct{Fields: map[string]*types.Value{
|
||||
toys: pbtypes.StringList([]string{"T Rex", "Fluffy Rabbit the Murderer"}),
|
||||
}}
|
||||
assertFilter(t, f, obj1, true)
|
||||
assertFilter(t, f, obj2, false)
|
||||
assertFilter(t, f, obj3, true)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue