Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GO-3964 ListRelationsByValue RPC #1552

Merged
merged 13 commits into from
Sep 24, 2024
650 changes: 344 additions & 306 deletions clientlibrary/service/service.pb.go

Large diffs are not rendered by default.

80 changes: 80 additions & 0 deletions core/block/relation.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,21 @@ import (
"context"
"fmt"
"strings"
"time"

"github.com/gogo/protobuf/types"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"

"github.com/anyproto/anytype-heart/core/block/cache"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
coresb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/database"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/addr"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)
Expand Down Expand Up @@ -56,3 +64,75 @@ func (s *Service) ObjectTypeRemoveRelations(ctx context.Context, objectTypeId st
return b.Apply(st)
})
}

func (s *Service) ListRelationsWithValue(spaceId string, value *types.Value) (keys []string, counters []int64, err error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it time for relationService?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes 😌

countersByKeys := make(map[string]int64)
detailHandlesValue := generateFilter(value)

err = s.objectStore.QueryAndProcess(database.Query{Filters: []*model.BlockContentDataviewFilter{{
RelationKey: bundle.RelationKeySpaceId.String(),
Condition: model.BlockContentDataviewFilter_Equal,
Value: pbtypes.String(spaceId),
}}}, func(details *types.Struct) {
for key, v := range details.Fields {
if detailHandlesValue(v) {
if counter, ok := countersByKeys[key]; ok {
countersByKeys[key] = counter + 1
} else {
countersByKeys[key] = 1
}
}
}
})

if err != nil {
return nil, nil, fmt.Errorf("failed to query objects: %w", err)
}

keys = maps.Keys(countersByKeys)
slices.Sort(keys)

for _, key := range keys {
counters = append(counters, countersByKeys[key])
}

return keys, counters, nil
}

func generateFilter(value *types.Value) func(v *types.Value) bool {
equalFilter := func(v *types.Value) bool {
return v.Equal(value)
}

stringValue := value.GetStringValue()
if stringValue == "" {
return equalFilter
}

sbt, err := typeprovider.SmartblockTypeFromID(stringValue)
if err != nil {
log.Errorf("failed to determine smartblock type: %v", err)
}

if sbt != coresb.SmartBlockTypeDate {
return equalFilter
}

start, err := addr.DateIDToDayStart(stringValue)
if err != nil {
log.Errorf("failed to convert date id to day start: %v", err)
return equalFilter
}

end := start.Add(24 * time.Hour)
startTimestamp := start.Unix()
endTimestamp := end.Unix()

return func(v *types.Value) bool {
numberValue := int64(v.GetNumberValue())
if numberValue >= startTimestamp && numberValue < endTimestamp {
return true
}
return equalFilter(v)
}
}
119 changes: 119 additions & 0 deletions core/block/relation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package block

import (
"testing"
"time"

"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"

"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/addr"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
)

const spaceId = "spaceId"

func relationObject(key domain.RelationKey, format model.RelationFormat) objectstore.TestObject {
return objectstore.TestObject{
bundle.RelationKeyId: pbtypes.String(key.URL()),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyLayout: pbtypes.Float64(float64(model.ObjectType_relation)),
bundle.RelationKeyRelationKey: pbtypes.String(key.String()),
bundle.RelationKeyRelationFormat: pbtypes.Int64(int64(format)),
}
}

func TestService_ListRelationsWithValue(t *testing.T) {
store := objectstore.NewStoreFixture(t)
store.AddObjects(t, []objectstore.TestObject{
// relations
relationObject(bundle.RelationKeyLastModifiedDate, model.RelationFormat_date),
relationObject(bundle.RelationKeyAddedDate, model.RelationFormat_date),
relationObject(bundle.RelationKeyCreatedDate, model.RelationFormat_date),
relationObject(bundle.RelationKeyLinks, model.RelationFormat_object),
relationObject(bundle.RelationKeyName, model.RelationFormat_longtext),
relationObject(bundle.RelationKeyIsHidden, model.RelationFormat_checkbox),
relationObject(bundle.RelationKeyIsFavorite, model.RelationFormat_checkbox),
relationObject("daysTillSummer", model.RelationFormat_number),
relationObject(bundle.RelationKeyCoverX, model.RelationFormat_number),
{
bundle.RelationKeyId: pbtypes.String("obj1"),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyCreatedDate: pbtypes.Int64(time.Now().Add(-5 * time.Minute).Unix()),
bundle.RelationKeyAddedDate: pbtypes.Int64(time.Now().Add(-3 * time.Minute).Unix()),
bundle.RelationKeyLastModifiedDate: pbtypes.Int64(time.Now().Add(-1 * time.Minute).Unix()),
bundle.RelationKeyIsFavorite: pbtypes.Bool(true),
"daysTillSummer": pbtypes.Int64(300),
bundle.RelationKeyLinks: pbtypes.StringList([]string{"obj2", "obj3"}),
},
{
bundle.RelationKeyId: pbtypes.String("obj2"),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyName: pbtypes.String(addr.TimeToID(time.Now())),
bundle.RelationKeyCreatedDate: pbtypes.Int64(time.Now().Add(-24*time.Hour - 5*time.Minute).Unix()),
bundle.RelationKeyAddedDate: pbtypes.Int64(time.Now().Add(-24*time.Hour - 3*time.Minute).Unix()),
bundle.RelationKeyLastModifiedDate: pbtypes.Int64(time.Now().Add(-1 * time.Minute).Unix()),
bundle.RelationKeyCoverX: pbtypes.Int64(300),
},
{
bundle.RelationKeyId: pbtypes.String("obj3"),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyIsHidden: pbtypes.Bool(true),
bundle.RelationKeyCreatedDate: pbtypes.Int64(time.Now().Add(-3 * time.Minute).Unix()),
bundle.RelationKeyLastModifiedDate: pbtypes.Int64(time.Now().Unix()),
bundle.RelationKeyIsFavorite: pbtypes.Bool(true),
bundle.RelationKeyCoverX: pbtypes.Int64(300),
},
})

bs := Service{objectStore: store}

for _, tc := range []struct {
name string
value *types.Value
expectedKeys []string
expectedCounters []int64
}{
{
"date object - today",
pbtypes.String(addr.TimeToID(time.Now())),
[]string{bundle.RelationKeyAddedDate.String(), bundle.RelationKeyCreatedDate.String(), bundle.RelationKeyLastModifiedDate.String(), bundle.RelationKeyName.String()},
[]int64{1, 2, 3, 1},
},
{
"date object - yesterday",
pbtypes.String(addr.TimeToID(time.Now().Add(-24 * time.Hour))),
[]string{bundle.RelationKeyAddedDate.String(), bundle.RelationKeyCreatedDate.String()},
[]int64{1, 1},
},
{
"number",
pbtypes.Int64(300),
[]string{bundle.RelationKeyCoverX.String(), "daysTillSummer"},
[]int64{2, 1},
},
{
"bool",
pbtypes.Bool(true),
[]string{bundle.RelationKeyIsFavorite.String(), bundle.RelationKeyIsHidden.String()},
[]int64{2, 1},
},
{
"string list",
pbtypes.StringList([]string{"obj2", "obj3"}),
[]string{bundle.RelationKeyLinks.String()},
[]int64{1},
},
} {
t.Run(tc.name, func(t *testing.T) {
keys, counters, err := bs.ListRelationsWithValue(spaceId, tc.value)
assert.NoError(t, err)
assert.Equal(t, tc.expectedKeys, keys)
assert.Equal(t, tc.expectedCounters, counters)
})
}
}
26 changes: 25 additions & 1 deletion core/relations.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,31 @@ func (mw *Middleware) RelationListRemoveOption(cctx context.Context, request *pb
return response(pb.RpcRelationListRemoveOptionResponseError_NULL, nil)
}

func (mw *Middleware) RelationOptions(cctx context.Context, request *pb.RpcRelationOptionsRequest) *pb.RpcRelationOptionsResponse {
func (mw *Middleware) RelationOptions(_ context.Context, _ *pb.RpcRelationOptionsRequest) *pb.RpcRelationOptionsResponse {
// TODO implement me
panic("implement me")
}

func (mw *Middleware) RelationListWithValue(_ context.Context, req *pb.RpcRelationListWithValueRequest) *pb.RpcRelationListWithValueResponse {
response := func(keys []string, counters []int64, err error) *pb.RpcRelationListWithValueResponse {
m := &pb.RpcRelationListWithValueResponse{Error: &pb.RpcRelationListWithValueResponseError{Code: pb.RpcRelationListWithValueResponseError_NULL}}
if err != nil {
m.Error.Description = getErrorDescription(err)
} else {
m.RelationKeys = keys
m.Counters = counters
}
return m
}

var (
keys []string
counters []int64
)

err := mw.doBlockService(func(bs *block.Service) (err error) {
keys, counters, err = bs.ListRelationsWithValue(req.SpaceId, req.Value)
return
})
return response(keys, counters, err)
}
78 changes: 78 additions & 0 deletions docs/proto.md
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,10 @@
- [Rpc.Relation.ListRemoveOption.Request](#anytype-Rpc-Relation-ListRemoveOption-Request)
- [Rpc.Relation.ListRemoveOption.Response](#anytype-Rpc-Relation-ListRemoveOption-Response)
- [Rpc.Relation.ListRemoveOption.Response.Error](#anytype-Rpc-Relation-ListRemoveOption-Response-Error)
- [Rpc.Relation.ListWithValue](#anytype-Rpc-Relation-ListWithValue)
- [Rpc.Relation.ListWithValue.Request](#anytype-Rpc-Relation-ListWithValue-Request)
- [Rpc.Relation.ListWithValue.Response](#anytype-Rpc-Relation-ListWithValue-Response)
- [Rpc.Relation.ListWithValue.Response.Error](#anytype-Rpc-Relation-ListWithValue-Response-Error)
- [Rpc.Relation.Options](#anytype-Rpc-Relation-Options)
- [Rpc.Relation.Options.Request](#anytype-Rpc-Relation-Options-Request)
- [Rpc.Relation.Options.Response](#anytype-Rpc-Relation-Options-Response)
Expand Down Expand Up @@ -1402,6 +1406,7 @@
- [Rpc.ObjectType.Relation.Remove.Response.Error.Code](#anytype-Rpc-ObjectType-Relation-Remove-Response-Error-Code)
- [Rpc.Process.Cancel.Response.Error.Code](#anytype-Rpc-Process-Cancel-Response-Error-Code)
- [Rpc.Relation.ListRemoveOption.Response.Error.Code](#anytype-Rpc-Relation-ListRemoveOption-Response-Error-Code)
- [Rpc.Relation.ListWithValue.Response.Error.Code](#anytype-Rpc-Relation-ListWithValue-Response-Error-Code)
- [Rpc.Relation.Options.Response.Error.Code](#anytype-Rpc-Relation-Options-Response-Error-Code)
- [Rpc.Space.Delete.Response.Error.Code](#anytype-Rpc-Space-Delete-Response-Error-Code)
- [Rpc.Space.InviteGenerate.Response.Error.Code](#anytype-Rpc-Space-InviteGenerate-Response-Error-Code)
Expand Down Expand Up @@ -1933,6 +1938,7 @@
| ObjectCreateRelationOption | [Rpc.Object.CreateRelationOption.Request](#anytype-Rpc-Object-CreateRelationOption-Request) | [Rpc.Object.CreateRelationOption.Response](#anytype-Rpc-Object-CreateRelationOption-Response) | |
| RelationListRemoveOption | [Rpc.Relation.ListRemoveOption.Request](#anytype-Rpc-Relation-ListRemoveOption-Request) | [Rpc.Relation.ListRemoveOption.Response](#anytype-Rpc-Relation-ListRemoveOption-Response) | |
| RelationOptions | [Rpc.Relation.Options.Request](#anytype-Rpc-Relation-Options-Request) | [Rpc.Relation.Options.Response](#anytype-Rpc-Relation-Options-Response) | |
| RelationListWithValue | [Rpc.Relation.ListWithValue.Request](#anytype-Rpc-Relation-ListWithValue-Request) | [Rpc.Relation.ListWithValue.Response](#anytype-Rpc-Relation-ListWithValue-Response) | |
| ObjectRelationAdd | [Rpc.ObjectRelation.Add.Request](#anytype-Rpc-ObjectRelation-Add-Request) | [Rpc.ObjectRelation.Add.Response](#anytype-Rpc-ObjectRelation-Add-Response) | Object Relations *** |
| ObjectRelationDelete | [Rpc.ObjectRelation.Delete.Request](#anytype-Rpc-ObjectRelation-Delete-Request) | [Rpc.ObjectRelation.Delete.Response](#anytype-Rpc-ObjectRelation-Delete-Response) | |
| ObjectRelationAddFeatured | [Rpc.ObjectRelation.AddFeatured.Request](#anytype-Rpc-ObjectRelation-AddFeatured-Request) | [Rpc.ObjectRelation.AddFeatured.Response](#anytype-Rpc-ObjectRelation-AddFeatured-Response) | |
Expand Down Expand Up @@ -16800,6 +16806,65 @@ Available undo/redo operations



<a name="anytype-Rpc-Relation-ListWithValue"></a>

### Rpc.Relation.ListWithValue







<a name="anytype-Rpc-Relation-ListWithValue-Request"></a>

### Rpc.Relation.ListWithValue.Request



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| spaceId | [string](#string) | | |
| value | [google.protobuf.Value](#google-protobuf-Value) | | |






<a name="anytype-Rpc-Relation-ListWithValue-Response"></a>

### Rpc.Relation.ListWithValue.Response



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| error | [Rpc.Relation.ListWithValue.Response.Error](#anytype-Rpc-Relation-ListWithValue-Response-Error) | | |
| relationKeys | [string](#string) | repeated | |
| counters | [int64](#int64) | repeated | |






<a name="anytype-Rpc-Relation-ListWithValue-Response-Error"></a>

### Rpc.Relation.ListWithValue.Response.Error



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| code | [Rpc.Relation.ListWithValue.Response.Error.Code](#anytype-Rpc-Relation-ListWithValue-Response-Error-Code) | | |
| description | [string](#string) | | |






<a name="anytype-Rpc-Relation-Options"></a>

### Rpc.Relation.Options
Expand Down Expand Up @@ -22182,6 +22247,19 @@ Middleware-to-front-end response, that can contain a NULL error or a non-NULL er



<a name="anytype-Rpc-Relation-ListWithValue-Response-Error-Code"></a>

### Rpc.Relation.ListWithValue.Response.Error.Code


| Name | Number | Description |
| ---- | ------ | ----------- |
| NULL | 0 | |
| UNKNOWN_ERROR | 1 | |
| BAD_INPUT | 2 | |



<a name="anytype-Rpc-Relation-Options-Response-Error-Code"></a>

### Rpc.Relation.Options.Response.Error.Code
Expand Down
Loading
Loading