mirror of
https://github.com/anyproto/anytype-heart.git
synced 2025-06-10 18:10:49 +09:00
Merge pull request #1560 from anyproto/go-3814-add-origin-to-files-via-reviser
GO-3814 Add recommendedRelations value revision for system types
This commit is contained in:
commit
931222e994
5 changed files with 139 additions and 5 deletions
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
|
||||
)
|
||||
|
||||
const TypeChecksum = "745e40062786ba9e43273b0009612a02af1eb9920ecaf6fab191f86b5cdd33f3"
|
||||
const TypeChecksum = "8b79add6b322acbcee123ad178c1aee523a2d9b9f219c391903530b29e554a1e"
|
||||
const (
|
||||
TypePrefix = "_ot"
|
||||
)
|
||||
|
@ -54,6 +54,7 @@ var (
|
|||
Readonly: true,
|
||||
RelationLinks: []*model.RelationLink{MustGetRelationLink(RelationKeyArtist), MustGetRelationLink(RelationKeyAudioAlbum), MustGetRelationLink(RelationKeyAudioAlbumTrackNumber), MustGetRelationLink(RelationKeyAudioGenre), MustGetRelationLink(RelationKeyAudioLyrics), MustGetRelationLink(RelationKeyReleasedYear), MustGetRelationLink(RelationKeySizeInBytes), MustGetRelationLink(RelationKeyFileMimeType), MustGetRelationLink(RelationKeyAddedDate), MustGetRelationLink(RelationKeyFileExt), MustGetRelationLink(RelationKeyOrigin)},
|
||||
RestrictObjectCreation: true,
|
||||
Revision: 1,
|
||||
Types: []model.SmartBlockType{model.SmartBlockType_File},
|
||||
Url: TypePrefix + "audio",
|
||||
},
|
||||
|
@ -144,6 +145,7 @@ var (
|
|||
Readonly: true,
|
||||
RelationLinks: []*model.RelationLink{MustGetRelationLink(RelationKeyFileMimeType), MustGetRelationLink(RelationKeySizeInBytes), MustGetRelationLink(RelationKeyAddedDate), MustGetRelationLink(RelationKeyFileExt), MustGetRelationLink(RelationKeyOrigin)},
|
||||
RestrictObjectCreation: true,
|
||||
Revision: 1,
|
||||
Types: []model.SmartBlockType{model.SmartBlockType_File},
|
||||
Url: TypePrefix + "file",
|
||||
},
|
||||
|
@ -167,6 +169,7 @@ var (
|
|||
Readonly: true,
|
||||
RelationLinks: []*model.RelationLink{MustGetRelationLink(RelationKeyFileMimeType), MustGetRelationLink(RelationKeyWidthInPixels), MustGetRelationLink(RelationKeyCamera), MustGetRelationLink(RelationKeyHeightInPixels), MustGetRelationLink(RelationKeySizeInBytes), MustGetRelationLink(RelationKeyCameraIso), MustGetRelationLink(RelationKeyAperture), MustGetRelationLink(RelationKeyExposure), MustGetRelationLink(RelationKeyAddedDate), MustGetRelationLink(RelationKeyFocalRatio), MustGetRelationLink(RelationKeyFileExt), MustGetRelationLink(RelationKeyOrigin)},
|
||||
RestrictObjectCreation: true,
|
||||
Revision: 1,
|
||||
Types: []model.SmartBlockType{model.SmartBlockType_File},
|
||||
Url: TypePrefix + "image",
|
||||
},
|
||||
|
@ -351,6 +354,7 @@ var (
|
|||
Readonly: true,
|
||||
RelationLinks: []*model.RelationLink{MustGetRelationLink(RelationKeySizeInBytes), MustGetRelationLink(RelationKeyFileMimeType), MustGetRelationLink(RelationKeyCamera), MustGetRelationLink(RelationKeyHeightInPixels), MustGetRelationLink(RelationKeyWidthInPixels), MustGetRelationLink(RelationKeyCameraIso), MustGetRelationLink(RelationKeyAperture), MustGetRelationLink(RelationKeyExposure), MustGetRelationLink(RelationKeyAddedDate), MustGetRelationLink(RelationKeyFileExt), MustGetRelationLink(RelationKeyOrigin)},
|
||||
RestrictObjectCreation: true,
|
||||
Revision: 1,
|
||||
Types: []model.SmartBlockType{model.SmartBlockType_File},
|
||||
Url: TypePrefix + "video",
|
||||
},
|
||||
|
|
|
@ -156,7 +156,8 @@
|
|||
"origin"
|
||||
],
|
||||
"description": "The recording of moving visual images",
|
||||
"restrictObjectCreation": true
|
||||
"restrictObjectCreation": true,
|
||||
"revision": 1
|
||||
},
|
||||
{
|
||||
"id": "dashboard",
|
||||
|
@ -358,7 +359,8 @@
|
|||
"origin"
|
||||
],
|
||||
"description": "A representation of the external form of a person or thing in art",
|
||||
"restrictObjectCreation": true
|
||||
"restrictObjectCreation": true,
|
||||
"revision": 1
|
||||
},
|
||||
{
|
||||
"id": "profile",
|
||||
|
@ -398,7 +400,8 @@
|
|||
"origin"
|
||||
],
|
||||
"description": "Sound when recorded, with ability to reproduce",
|
||||
"restrictObjectCreation": true
|
||||
"restrictObjectCreation": true,
|
||||
"revision": 1
|
||||
},
|
||||
{
|
||||
"id": "goal",
|
||||
|
@ -435,7 +438,8 @@
|
|||
"origin"
|
||||
],
|
||||
"description": "Computer resource for recording data in a computer storage device",
|
||||
"restrictObjectCreation": true
|
||||
"restrictObjectCreation": true,
|
||||
"revision": 1
|
||||
},
|
||||
{
|
||||
"id": "project",
|
||||
|
|
|
@ -4,9 +4,11 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
|
||||
"github.com/anyproto/anytype-heart/core/domain"
|
||||
)
|
||||
|
||||
type SpaceWithCtx interface {
|
||||
DoCtx(ctx context.Context, objectId string, apply func(sb smartblock.SmartBlock) error) error
|
||||
Id() string
|
||||
DeriveObjectID(ctx context.Context, uniqueKey domain.UniqueKey) (id string, err error)
|
||||
}
|
||||
|
|
|
@ -4,8 +4,10 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/anyproto/any-sync/app/logger"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/gogo/protobuf/types"
|
||||
"github.com/samber/lo"
|
||||
"go.uber.org/zap"
|
||||
|
@ -20,6 +22,7 @@ import (
|
|||
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
|
||||
"github.com/anyproto/anytype-heart/space/internal/components/dependencies"
|
||||
"github.com/anyproto/anytype-heart/util/pbtypes"
|
||||
"github.com/anyproto/anytype-heart/util/slice"
|
||||
)
|
||||
|
||||
type detailsSettable interface {
|
||||
|
@ -100,6 +103,16 @@ func reviseSystemObject(ctx context.Context, log logger.CtxLogger, space depende
|
|||
return false, nil
|
||||
}
|
||||
details := buildDiffDetails(marketObject, localObject)
|
||||
|
||||
recRelsDetail, err := checkRecommendedRelations(ctx, space, marketObject, localObject)
|
||||
if err != nil {
|
||||
log.Error("failed to check recommended relations", zap.Error(err))
|
||||
}
|
||||
|
||||
if recRelsDetail != nil {
|
||||
details = append(details, recRelsDetail)
|
||||
}
|
||||
|
||||
if len(details) != 0 {
|
||||
log.Debug("updating system object", zap.String("source", source), zap.String("space", space.Id()))
|
||||
if err := space.DoCtx(ctx, pbtypes.GetString(localObject, bundle.RelationKeyId.String()), func(sb smartblock.SmartBlock) error {
|
||||
|
@ -150,3 +163,44 @@ func buildDiffDetails(origin, current *types.Struct) (details []*model.Detail) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkRecommendedRelations(ctx context.Context, space dependencies.SpaceWithCtx, origin, current *types.Struct) (newValue *model.Detail, err error) {
|
||||
localIds := pbtypes.GetStringList(current, bundle.RelationKeyRecommendedRelations.String())
|
||||
bundledIds := pbtypes.GetStringList(origin, bundle.RelationKeyRecommendedRelations.String())
|
||||
|
||||
newIds := make([]string, 0, len(bundledIds))
|
||||
for _, bundledId := range bundledIds {
|
||||
if !strings.HasPrefix(bundledId, addr.BundledRelationURLPrefix) {
|
||||
return nil, fmt.Errorf("invalid recommended bundled relation id: %s. %s prefix is expected",
|
||||
bundledId, addr.BundledRelationURLPrefix)
|
||||
}
|
||||
key := strings.TrimPrefix(bundledId, addr.BundledRelationURLPrefix)
|
||||
uk, err := domain.NewUniqueKey(coresb.SmartBlockTypeRelation, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// we should add only system relations to object types, because non-system could be not installed to space yet
|
||||
if !lo.Contains(bundle.SystemRelations, domain.RelationKey(uk.InternalKey())) {
|
||||
log.Debug("recommended relation is not system, so we are not adding it to the type object", zap.String("relation key", key))
|
||||
continue
|
||||
}
|
||||
|
||||
id, err := space.DeriveObjectID(ctx, uk)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive recommended relation with key '%s': %w", key, err)
|
||||
}
|
||||
|
||||
newIds = append(newIds, id)
|
||||
}
|
||||
|
||||
_, added := slice.DifferenceRemovedAdded(localIds, newIds)
|
||||
if len(added) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &model.Detail{
|
||||
Key: bundle.RelationKeyRecommendedRelations.String(),
|
||||
Value: pbtypes.StringList(append(localIds, added...)),
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"github.com/anyproto/anytype-heart/core/domain"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/localstore/addr"
|
||||
mock_space "github.com/anyproto/anytype-heart/space/clientspace/mock_clientspace"
|
||||
"github.com/anyproto/anytype-heart/util/pbtypes"
|
||||
)
|
||||
|
@ -217,4 +219,72 @@ func TestReviseSystemObject(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.True(t, toRevise)
|
||||
})
|
||||
|
||||
t.Run("recommendedRelations list is updated", func(t *testing.T) {
|
||||
// given
|
||||
rel := &types.Struct{Fields: map[string]*types.Value{
|
||||
bundle.RelationKeyRevision.String(): pbtypes.Int64(1),
|
||||
bundle.RelationKeySourceObject.String(): pbtypes.String("_otpage"),
|
||||
bundle.RelationKeyUniqueKey.String(): pbtypes.String("ot-page"),
|
||||
bundle.RelationKeyRecommendedRelations.String(): pbtypes.StringList([]string{"rel-name"}),
|
||||
}}
|
||||
space := mock_space.NewMockSpace(t)
|
||||
space.EXPECT().DoCtx(mock.Anything, mock.Anything, mock.Anything).Times(1).Return(nil)
|
||||
space.EXPECT().Id().Times(1).Return("")
|
||||
space.EXPECT().DeriveObjectID(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, key domain.UniqueKey) (string, error) {
|
||||
return addr.ObjectTypeKeyToIdPrefix + key.InternalKey(), nil
|
||||
}).Maybe()
|
||||
|
||||
// when
|
||||
marketObjects["_otpage"].Fields["recommendedRelations"] = pbtypes.StringList([]string{"_brname", "_brorigin"})
|
||||
toRevise, err := reviseSystemObject(ctx, log, space, rel, marketObjects)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, toRevise)
|
||||
})
|
||||
|
||||
t.Run("recommendedRelations list is not updated", func(t *testing.T) {
|
||||
// given
|
||||
rel := &types.Struct{Fields: map[string]*types.Value{
|
||||
bundle.RelationKeyRevision.String(): pbtypes.Int64(2),
|
||||
bundle.RelationKeySourceObject.String(): pbtypes.String("_otpage"),
|
||||
bundle.RelationKeyUniqueKey.String(): pbtypes.String("ot-page"),
|
||||
bundle.RelationKeyRecommendedRelations.String(): pbtypes.StringList([]string{"rel-name", "rel-tag"}),
|
||||
}}
|
||||
space := mock_space.NewMockSpace(t)
|
||||
space.EXPECT().DeriveObjectID(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, key domain.UniqueKey) (string, error) {
|
||||
return addr.ObjectTypeKeyToIdPrefix + key.InternalKey(), nil
|
||||
}).Maybe()
|
||||
|
||||
// when
|
||||
marketObjects["_otpage"].Fields["recommendedRelations"] = pbtypes.StringList([]string{"_brname", "_brtag"})
|
||||
toRevise, err := reviseSystemObject(ctx, log, space, rel, marketObjects)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, toRevise)
|
||||
})
|
||||
|
||||
t.Run("recommendedRelations list is updated by not system relations", func(t *testing.T) {
|
||||
// given
|
||||
rel := &types.Struct{Fields: map[string]*types.Value{
|
||||
bundle.RelationKeyRevision.String(): pbtypes.Int64(2),
|
||||
bundle.RelationKeySourceObject.String(): pbtypes.String("_otpage"),
|
||||
bundle.RelationKeyUniqueKey.String(): pbtypes.String("ot-page"),
|
||||
bundle.RelationKeyRecommendedRelations.String(): pbtypes.StringList([]string{"rel-name"}),
|
||||
}}
|
||||
space := mock_space.NewMockSpace(t)
|
||||
space.EXPECT().DeriveObjectID(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, key domain.UniqueKey) (string, error) {
|
||||
return addr.ObjectTypeKeyToIdPrefix + key.InternalKey(), nil
|
||||
}).Maybe()
|
||||
|
||||
// when
|
||||
marketObjects["_otpage"].Fields["recommendedRelations"] = pbtypes.StringList([]string{"_brname", "_brtag"})
|
||||
toRevise, err := reviseSystemObject(ctx, log, space, rel, marketObjects)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, toRevise)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue