1
0
Fork 0
mirror of https://github.com/anyproto/anytype-heart.git synced 2025-06-09 17:44:59 +09:00

GO-4459 Merge branch 'main' into go-4459-implement-first-stage-of-anytype-rest-api

This commit is contained in:
Jannis Metrikat 2024-12-18 20:09:02 +01:00
commit d2ce601810
No known key found for this signature in database
GPG key ID: B223CAC5AAF85615
385 changed files with 8813 additions and 9833 deletions

View file

@ -2,10 +2,14 @@
on:
workflow_dispatch:
inputs:
run-on-runner:
description: 'Specify the runner to use'
run-on-runner-mac:
description: 'Specify the runner to use on MacOS'
required: true
default: 'ARM64'
run-on-runner-win:
description: 'Specify the runner to use on Windows'
required: true
default: 'windows-perftests'
perf-test:
description: 'Run perf test times'
required: true
@ -17,7 +21,6 @@ on:
include:
- 'main'
permissions:
actions: 'write'
contents: 'write'
@ -25,7 +28,7 @@ permissions:
name: Perf tests
jobs:
build:
perftests-macos:
timeout-minutes: 60
runs-on: 'ARM64'
steps:
@ -76,7 +79,7 @@ jobs:
RUN_COUNT=${{ github.event.inputs.perf-test }}
if [[ "${{ github.event_name }}" == "schedule" ]]; then
RUN_COUNT=10
fi
fi
echo $PERF_CONFIG_STAGING > config.json
mv .github/staging_fake.yml staging_fake.yml
PERF_CONFIG=$PWD/config.json
@ -97,6 +100,165 @@ jobs:
- name: Archive perf tests results
uses: actions/upload-artifact@v4
with:
name: traces
name: traces-macos
path: |
*.log
*.log
perftests-windows:
timeout-minutes: 60
runs-on: 'windows-perftests'
steps:
- name: Install windows utils
run: C:\ProgramData\chocolatey\bin\choco install gzip mingw git -y
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
cache: false
- name: Setup Go env
run: |
go version
echo GOPATH=$(go env GOPATH) >> $env:GITHUB_ENV
echo GOBIN=$(go env GOPATH)\bin >> $env:GITHUB_ENV
echo $(go env GOPATH)\bin >> $env:GITHUB_PATH
- name: Checkout
uses: actions/checkout@v4.2.2
- name: Set env vars
env:
UNSPLASH_KEY: ${{ secrets.UNSPLASH_KEY }}
INHOUSE_KEY: ${{ secrets.INHOUSE_KEY }}
run: |
$GIT_SUMMARY = git describe --tags --always
echo "FLAGS=-X github.com/anyproto/anytype-heart/util/vcs.GitSummary=$GIT_SUMMARY -X github.com/anyproto/anytype-heart/metrics.DefaultInHouseKey=$env:INHOUSE_KEY -X github.com/anyproto/anytype-heart/util/unsplash.DefaultToken=$env:UNSPLASH_KEY" >> $env:GITHUB_ENV
if ($env:GITHUB_EVENT_NAME -eq "workflow_dispatch") {
$VERSION = ${{ github.event.inputs.alpha_version }}
if (-not $VERSION) {
$VERSION = git rev-parse --short HEAD
}
}
if (-not $VERSION) {
$VERSION = ($env:GITHUB_REF -split "/")[-1]
}
echo "VERSION=$VERSION" >> $env:GITHUB_ENV
echo "MAVEN_ARTIFACT_VERSION=$VERSION" >> $env:GITHUB_ENV
echo "GOPRIVATE=github.com/anyproto" >> $env:GITHUB_ENV
echo "$(Get-Location)\deps" >> $env:GITHUB_PATH
echo "$env:GOBIN" >> $env:GITHUB_PATH
git config --global url."https://${{ secrets.ANYTYPE_PAT }}@github.com/".insteadOf "https://github.com/"
- name: Go mod download
run: |
go mod download
- name: Setup network config
env:
CUSTOM_NETWORK_FILE: ./core/anytype/config/nodes/custom.yml
run: |
if (-not $env:ANY_SYNC_NETWORK) {
echo "Using the default production Any Sync Network"
} elseif (-not (Test-Path $env:ANY_SYNC_NETWORK)) {
echo "Network configuration file not found at $env:ANY_SYNC_NETWORK"
exit 1
} else {
echo "Using Any Sync Network configuration at $env:ANY_SYNC_NETWORK"
Copy-Item -Path $env:ANY_SYNC_NETWORK -Destination $CUSTOM_NETWORK_FILE -Force
}
- name: Check and download tantivy
env:
TANTIVY_GO_PATH: ../tantivy-go
OUTPUT_DIR: deps/libs
REPO: anyproto/tantivy-go
run: |
$TANTIVY_VERSION = (Get-Content go.mod | Select-String "github.com/anyproto/tantivy-go" | ForEach-Object { ($_ -split " ")[1] }).Trim()
$TANTIVY_LIBS = @(
"windows-amd64.tar.gz"
)
if (-not (Test-Path "$env:OUTPUT_DIR/.verified") -or (Get-Content "$env:OUTPUT_DIR/.verified").Trim() -ne $TANTIVY_VERSION) {
if (Test-Path "$env:OUTPUT_DIR") {
Remove-Item -Recurse -Force "$env:OUTPUT_DIR/*"
}
if (-not (Test-Path "$env:OUTPUT_DIR")) {
New-Item -ItemType Directory -Path "$env:OUTPUT_DIR" | Out-Null
}
foreach ($lib in $TANTIVY_LIBS) {
$downloadUrl = "https://github.com/$env:REPO/releases/download/$TANTIVY_VERSION/$lib"
$localFilePath = "$env:OUTPUT_DIR/$lib"
Invoke-WebRequest -Uri $downloadUrl -OutFile $localFilePath
$extractDir = "$env:OUTPUT_DIR/$($lib -replace '.tar.gz', '')"
if (-not (Test-Path $extractDir)) {
New-Item -ItemType Directory -Path $extractDir | Out-Null
}
tar -C $extractDir -xvzf $localFilePath
}
Get-ChildItem -Path "$env:OUTPUT_DIR" -Filter "*.tar.gz" | Remove-Item -Force
Set-Content -Path "$env:OUTPUT_DIR/.verified" -Value $TANTIVY_VERSION
echo "Tantivy libraries updated successfully."
} else {
echo "Tantivy libraries are up to date."
}
- name: Install grpcurl and govvv
run: |
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
go install github.com/ahmetb/govvv@v0.2.0
- name: Run perf tests
run: |
echo "Running perf tests in staging mode..."
if ($env:GITHUB_EVENT_NAME -eq "schedule") {
$RUN_COUNT = 10
} elseif ("${{ github.event.inputs.perf-test }}" -ne "") {
$RUN_COUNT = "${{ github.event.inputs.perf-test }}"
} else {
$RUN_COUNT = 10 # default value
}
echo "Current RUN_COUNT: $RUN_COUNT"
echo "Current Github event name: $env:GITHUB_EVENT_NAME"
Set-Content -Path config.json -Value $env:PERF_CONFIG_STAGING
(Get-Content config.json).Replace('"/Users/user1/account30000"', '"C:/Users/' + $env:USERNAME + '"') | Set-Content -Path config.json
Move-Item -Path .\.github\staging_fake.yml -Destination .\staging_fake.yml -Force
$PERF_CONFIG = ((Get-Location).Path -replace '\\', '/') + "/config.json"
Set-Location cmd\perfstand\account_create
$env:CGO_ENABLED = "1"
go run main.go $PERF_CONFIG $RUN_COUNT
Set-Location ..\account_select
go run main.go $PERF_CONFIG $RUN_COUNT
echo "Perf test with staging - done"
echo "Running perf tests in local mode..."
Set-Location (Resolve-Path "../../..")
Set-Content -Path config.json -Value $env:PERF_CONFIG_LOCAL
(Get-Content config.json).Replace('"/Users/user1/account30000"', '"C:/Users/' + $env:USERNAME + '"') | Set-Content -Path config.json
Set-Location cmd\perfstand\account_create
$env:CGO_ENABLED = "1"
go run main.go $PERF_CONFIG $RUN_COUNT
Set-Location ..\account_select
go run main.go $PERF_CONFIG $RUN_COUNT
echo "Perf test in local mode - done"
env:
PERF_CONFIG_STAGING: ${{ secrets.PERF_CONFIG_STAGING }}
PERF_CONFIG_LOCAL: ${{ secrets.PERF_CONFIG_LOCAL }}
CH_API_KEY: ${{ secrets.CH_PERF_API_KEY }}
- name: Clean /tmp
run: |
echo "Clean workspaces in /Temp"
Get-ChildItem "C:/Users/$env:USERNAME/AppData/Local/Temp/" -Directory -Force | Where-Object { $_.Name -like "workspace*" } | ForEach-Object { Remove-Item $_.FullName -Recurse -Force -ErrorAction SilentlyContinue }
- name: Archive perf tests results
uses: actions/upload-artifact@v4
with:
name: traces-win
path: |
*.log

View file

@ -43,6 +43,9 @@ packages:
github.com/anyproto/anytype-heart/core/block/import/common:
interfaces:
Converter:
github.com/anyproto/anytype-heart/core/block/import/web/parsers:
interfaces:
Parser:
github.com/anyproto/anytype-heart/core/block/restriction:
interfaces:
Service:

View file

@ -5,6 +5,7 @@ import (
"fmt"
"os"
"os/exec"
"runtime"
"go.uber.org/atomic"
@ -58,10 +59,18 @@ func main() {
func iterate(prep *input, result internal.PerfResult) error {
workspace, err := os.MkdirTemp("", "workspace")
prep.Workspace = workspace
if err != nil {
return err
}
if runtime.GOOS == "windows" {
workspace, err = internal.WinFixPath(workspace)
if err != nil {
return err
}
}
prep.Workspace = workspace
defer os.RemoveAll(workspace)
fmt.Println("Created temporary directory:", workspace)
@ -79,7 +88,13 @@ func iterate(prep *input, result internal.PerfResult) error {
return err
}
walletStr, err := exec.Command("bash", "-c", internal.GrpcWalletCreate(workspace)).Output()
var cmd *exec.Cmd
if runtime.GOOS == "windows" {
cmd = exec.Command("powershell", "-Command", internal.GrpcWalletCreate(workspace))
} else {
cmd = exec.Command("bash", "-c", internal.GrpcWalletCreate(workspace))
}
walletStr, err := cmd.Output()
if err != nil {
return err
}

View file

@ -80,12 +80,23 @@ func SendResultsToHttp(apiKey string, events []Event) error {
}
func KillServer() error {
return ExecuteCommand("kill -9 $(lsof -i :31007 -t) ; echo \"Server killed\"")
var cmd string
if runtime.GOOS == "windows" {
cmd = `(Get-NetTCPConnection -LocalPort 31007 -State Listen | Select-Object -ExpandProperty OwningProcess | ForEach-Object { Stop-Process -Id $_ -Force -ErrorAction SilentlyContinue }) ; Write-Host "Server killed"`
} else {
cmd = "kill -9 $(lsof -i :31007 -t) ; echo \"Server killed\""
}
return ExecuteCommand(cmd)
}
func ExecuteCommand(command string) error {
fmt.Println(command)
cmd := exec.Command("bash", "-c", command)
var cmd *exec.Cmd
if runtime.GOOS == "windows" {
cmd = exec.Command("powershell", "-Command", command)
} else {
cmd = exec.Command("bash", "-c", command)
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
@ -96,7 +107,10 @@ func ExecuteCommand(command string) error {
}
func UnpackZip(path string, workspace string) error {
return ExecuteCommand("unzip -o " + path + " -d " + workspace)
if runtime.GOOS == "windows" {
return ExecuteCommand("Expand-Archive -Path " + path + " -DestinationPath " + workspace + " -Force")
}
return ExecuteCommand("unzip -qq -o " + path + " -d " + workspace)
}
func BuildAnytype(err error) error {
@ -117,6 +131,10 @@ func LoadEnv(env string) (string, error) {
return res, nil
}
func WinFixPath(winPath string) (string, error) {
return strings.ReplaceAll(winPath, "\\", "/"), nil
}
func SetupWd() (string, error) {
err := os.Chdir("../../..")
if err != nil {
@ -128,22 +146,42 @@ func SetupWd() (string, error) {
return "", err
}
if runtime.GOOS == "windows" {
getwd, err = WinFixPath(getwd)
if err != nil {
return "", err
}
}
fmt.Println("Current working directory:", getwd)
return getwd, nil
}
func GrpcWorkspaceOpen(workspace string) string {
if runtime.GOOS == "windows" {
return `cmd.exe /c 'grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d "{\"spaceId\":\"` + workspace + `\"}" localhost:31007 anytype.ClientCommands.WorkspaceOpen'`
}
return `grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d '{
"spaceId": "` + workspace + `"
}' localhost:31007 anytype.ClientCommands.WorkspaceOpen`
}
func GrpcWorkspaceCreate() string {
if runtime.GOOS == "windows" {
return `cmd.exe /c 'grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d "{}" localhost:31007 anytype.ClientCommands.WorkspaceCreate'`
}
return `grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d '{
}' localhost:31007 anytype.ClientCommands.WorkspaceCreate`
}
func GrpcAccountSelect(accHash, workspace, networkMode, staging string) string {
if runtime.GOOS == "windows" {
staging, err := WinFixPath(staging)
if err != nil {
return "Error: " + err.Error()
}
return `cmd.exe /c 'grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d "{\"id\":\"` + accHash + `\",\"rootPath\":\"` + workspace + `\",\"disableLocalNetworkSync\":false,\"networkMode\":` + networkMode + `,\"networkCustomConfigFilePath\":\"` + staging + `\"}" localhost:31007 anytype.ClientCommands.AccountSelect'`
}
return `grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d '{
"id": "` + accHash + `",
"rootPath": "` + workspace + `",
@ -154,12 +192,18 @@ func GrpcAccountSelect(accHash, workspace, networkMode, staging string) string {
}
func GrpcWalletCreateSession(mnemonic string) string {
if runtime.GOOS == "windows" {
return `cmd.exe /c 'grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d "{\"mnemonic\":\"` + mnemonic + `\"}" localhost:31007 anytype.ClientCommands.WalletCreateSession'`
}
return `grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d '{
"mnemonic": "` + mnemonic + `"
}' localhost:31007 anytype.ClientCommands.WalletCreateSession`
}
func GrpcWalletRecover(workspace, mnemonic string) string {
if runtime.GOOS == "windows" {
return `cmd.exe /c 'grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d "{\"rootPath\":\"` + workspace + `\",\"mnemonic\":\"` + mnemonic + `\"}" localhost:31007 anytype.ClientCommands.WalletRecover'`
}
return `grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d '{
"rootPath": "` + workspace + `",
"mnemonic": "` + mnemonic + `"
@ -167,12 +211,22 @@ func GrpcWalletRecover(workspace, mnemonic string) string {
}
func GrpcWalletCreate(workspace string) string {
if runtime.GOOS == "windows" {
return `cmd.exe /c 'grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d "{\"rootPath\":\"` + workspace + `\"}" localhost:31007 anytype.ClientCommands.WalletCreate'`
}
return `grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d '{
"rootPath": "` + workspace + `"
}' localhost:31007 anytype.ClientCommands.WalletCreate`
}
func GrpcAccountCreate(workspace, networkMode, staging string) string {
if runtime.GOOS == "windows" {
staging, err := WinFixPath(staging)
if err != nil {
return "Error: " + err.Error()
}
return `cmd.exe /c 'grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d "{\"icon\":13,\"networkMode\":` + networkMode + `,\"storePath\":\"` + workspace + `\",\"networkCustomConfigFilePath\":\"` + staging + `\"}" localhost:31007 anytype.ClientCommands.AccountCreate'`
}
return `grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d '{
"icon": 13,
"networkMode": ` + networkMode + `,
@ -182,6 +236,9 @@ func GrpcAccountCreate(workspace, networkMode, staging string) string {
}
func GrpcInitialSetParameters() string {
if runtime.GOOS == "windows" {
return `cmd.exe /c 'grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d "{\"platform\":\"test\",\"version\":\"0.0.0-test\"}" localhost:31007 anytype.ClientCommands.InitialSetParameters'`
}
return `grpcurl -import-path ../anytype-heart/ -proto pb/protos/service/service.proto -plaintext -d '{
"platform": "test",
"version": "0.0.0-test"
@ -189,7 +246,12 @@ func GrpcInitialSetParameters() string {
}
func StartAnytypeBackground() error {
runServer := exec.Command("./dist/server")
var runServer *exec.Cmd
if runtime.GOOS == "windows" {
runServer = exec.Command("./dist/server.exe")
} else {
runServer = exec.Command("./dist/server")
}
runServer.Stdout = os.Stdout
runServer.Stderr = os.Stderr
runServer.Env = append(os.Environ(), `ANYPROF=:6060`)
@ -200,7 +262,15 @@ func StartAnytypeBackground() error {
// Wait for the server to start
for {
err = ExecuteCommand(`pids=$(lsof -i :31007 -t) && [ -n "$pids" ] && echo "Found process: $pids" || { echo "No process found"; exit 1; }`)
var cmd string
if runtime.GOOS == "windows" {
cmd = `$pids = (Get-NetTCPConnection -LocalPort 31007 -State Listen -ErrorAction SilentlyContinue | Select-Object -ExpandProperty OwningProcess); if ($pids) { Write-Output "Found process: $pids" } else { Write-Output "No process found"; exit 1 }`
} else {
cmd = `pids=$(lsof -i :31007 -t) && [ -n "$pids" ] && echo "Found process: $pids" || { echo "No process found"; exit 1; }`
}
err = ExecuteCommand(cmd)
if err == nil {
break
} else {
@ -466,8 +536,18 @@ func Prepare[T BasicInputtable](prep T, f func(T) error) error {
if err != nil {
return err
}
fmt.Println("Created temporary directory:", workspace)
prep.SetWorkspace(workspace)
if runtime.GOOS == "windows" {
winWorkspace, err := WinFixPath(workspace)
if err != nil {
return err
}
fmt.Println("Created temporary directory:", winWorkspace)
prep.SetWorkspace(winWorkspace)
} else {
fmt.Println("Created temporary directory:", workspace)
prep.SetWorkspace(workspace)
}
_, err = SetupWd()
if err != nil {
@ -486,10 +566,29 @@ func Prepare[T BasicInputtable](prep T, f func(T) error) error {
}
}
err = BuildAnytype(err)
if err != nil {
return err
if runtime.GOOS == "windows" {
fmt.Printf("Build GRPC server on Windows...")
command := `
$Env:GOOS="windows";
$Env:GOARCH="amd64";
$Env:CGO_ENABLED="1";
$Env:CC="x86_64-w64-mingw32-gcc";
$Env:CXX="x86_64-w64-mingw32-g++";
go build -o dist/server.exe -ldflags "$env:FLAGS -linkmode external -extldflags=-static" --tags "noauth nosigar nowatchdog" $env:BUILD_FLAGS github.com/anyproto/anytype-heart/cmd/grpcserver
`
err := ExecuteCommand(command)
if err != nil {
fmt.Printf("Error on building: %v\n", err)
} else {
fmt.Println("Build completed successfully")
}
} else {
err = BuildAnytype(err)
if err != nil {
return err
}
}
return nil
}

View file

@ -238,7 +238,7 @@ func collectUseCaseInfo(files []*zip.File, fileName string) (info *useCaseInfo,
key := strings.TrimPrefix(uk, addr.RelationKeyToIdPrefix)
info.relations[id] = domain.RelationKey(key)
format := pbtypes.GetInt64(snapshot.Snapshot.Data.Details, bundle.RelationKeyRelationFormat.String())
if !bundle.HasRelation(key) {
if !bundle.HasRelation(domain.RelationKey(key)) {
info.customTypesAndRelations[key] = customInfo{id: id, isUsed: false, relationFormat: model.RelationFormat(format)}
}
case model.SmartBlockType_STType:
@ -259,7 +259,7 @@ func collectUseCaseInfo(files []*zip.File, fileName string) (info *useCaseInfo,
key := strings.TrimPrefix(id, addr.RelationKeyToIdPrefix)
info.relations[id] = domain.RelationKey(key)
format := pbtypes.GetInt64(snapshot.Snapshot.Data.Details, bundle.RelationKeyRelationFormat.String())
if !bundle.HasRelation(key) {
if !bundle.HasRelation(domain.RelationKey(key)) {
info.customTypesAndRelations[key] = customInfo{id: id, isUsed: false, relationFormat: model.RelationFormat(format)}
}
}

View file

@ -7,6 +7,7 @@ import (
"strings"
"github.com/hashicorp/go-multierror"
"github.com/ipfs/go-cid"
"github.com/samber/lo"
"github.com/anyproto/anytype-heart/core/block/editor/widget"
@ -44,7 +45,7 @@ func validateRelationLinks(s *pb.SnapshotWithType, info *useCaseInfo) (err error
id := pbtypes.GetString(s.Snapshot.Data.Details, bundle.RelationKeyId.String())
linksToDelete := make([]keyWithIndex, 0)
for i, rel := range s.Snapshot.Data.RelationLinks {
if bundle.HasRelation(rel.Key) {
if bundle.HasRelation(domain.RelationKey(rel.Key)) {
continue
}
if _, found := info.customTypesAndRelations[rel.Key]; found {
@ -123,7 +124,7 @@ func validateDetails(s *pb.SnapshotWithType, info *useCaseInfo) (err error) {
values := pbtypes.GetStringListValue(v)
for _, val := range values {
if bundle.HasRelation(strings.TrimPrefix(val, addr.RelationKeyToIdPrefix)) ||
if bundle.HasRelation(domain.RelationKey(strings.TrimPrefix(val, addr.RelationKeyToIdPrefix))) ||
bundle.HasObjectTypeByKey(domain.TypeKey(strings.TrimPrefix(val, addr.ObjectTypeKeyToIdPrefix))) || val == addr.AnytypeProfileId {
continue
}
@ -213,6 +214,39 @@ func validateBlockLinks(s *pb.SnapshotWithType, info *useCaseInfo) (err error) {
return err
}
func validateFileKeys(s *pb.SnapshotWithType, _ *useCaseInfo) (err error) {
id := pbtypes.GetString(s.Snapshot.Data.Details, bundle.RelationKeyId.String())
for _, r := range s.Snapshot.Data.RelationLinks {
if r.Format == model.RelationFormat_file || r.Key == bundle.RelationKeyCoverId.String() {
for _, hash := range pbtypes.GetStringList(s.Snapshot.GetData().GetDetails(), r.Key) {
if r.Format != model.RelationFormat_file {
_, err := cid.Parse(hash)
if err != nil {
continue
}
}
if !snapshotHasKeyForHash(s, hash) {
err = multierror.Append(err, fmt.Errorf("object '%s' has file detail '%s' has hash '%s' which keys are not in the snapshot", id, r.Key, hash))
}
}
}
}
for _, b := range s.Snapshot.Data.Blocks {
if v, ok := simple.New(b).(simple.FileHashes); ok {
hashes := v.FillFileHashes([]string{})
if len(hashes) == 0 {
continue
}
for _, hash := range hashes {
if !snapshotHasKeyForHash(s, hash) {
err = multierror.Append(err, fmt.Errorf("file block '%s' of object '%s' has hash '%s' which keys are not in the snapshot", b.Id, id, hash))
}
}
}
}
return err
}
func validateDeleted(s *pb.SnapshotWithType, _ *useCaseInfo) error {
id := pbtypes.GetString(s.Snapshot.Data.Details, bundle.RelationKeyId.String())
@ -240,7 +274,7 @@ func validateRelationOption(s *pb.SnapshotWithType, info *useCaseInfo) error {
}
key := pbtypes.GetString(s.Snapshot.Data.Details, bundle.RelationKeyRelationKey.String())
if bundle.HasRelation(key) {
if bundle.HasRelation(domain.RelationKey(key)) {
return nil
}
@ -261,6 +295,15 @@ func getRelationLinkByKey(links []*model.RelationLink, key string) *model.Relati
return nil
}
func snapshotHasKeyForHash(s *pb.SnapshotWithType, hash string) bool {
for _, k := range s.Snapshot.FileKeys {
if k.Hash == hash && len(k.Keys) > 0 {
return true
}
}
return false
}
func isLinkRelation(k string) bool {
return k == bundle.RelationKeyLinks.String() || k == bundle.RelationKeySourceObject.String() || k == bundle.RelationKeyBacklinks.String()
}

View file

@ -15,7 +15,6 @@ import (
"github.com/anyproto/any-sync/coordinator/coordinatorproto"
"github.com/anyproto/any-sync/nodeconf"
"github.com/anyproto/any-sync/util/crypto"
"github.com/gogo/protobuf/types"
"github.com/ipfs/go-cid"
"github.com/anyproto/anytype-heart/core/anytype/account"
@ -27,7 +26,6 @@ import (
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/space/spaceinfo"
"github.com/anyproto/anytype-heart/space/techspace"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
const CName = "common.acl.aclservice"
@ -368,10 +366,10 @@ func (a *aclService) Join(ctx context.Context, spaceId, networkId string, invite
if err != nil {
return convertedOrInternalError("join space", err)
}
err = a.spaceService.TechSpace().SpaceViewSetData(ctx, spaceId, &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyName.String(): pbtypes.String(invitePayload.SpaceName),
bundle.RelationKeyIconImage.String(): pbtypes.String(invitePayload.SpaceIconCid),
}})
err = a.spaceService.TechSpace().SpaceViewSetData(ctx, spaceId,
domain.NewDetails().
SetString(bundle.RelationKeyName, invitePayload.SpaceName).
SetString(bundle.RelationKeyIconImage, invitePayload.SpaceIconCid))
if err != nil {
return convertedOrInternalError("set space data", err)
}

View file

@ -4,6 +4,7 @@ import (
"fmt"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
)
type Profile struct {
@ -36,20 +37,9 @@ func (s *service) ProfileInfo() (Profile, error) {
if err != nil {
return profile, err
}
if profileDetails != nil && profileDetails.Details != nil && profileDetails.Details.Fields != nil {
for _, s := range []struct {
field string
receiver *string
}{
{"name", &profile.Name},
{"iconImage", &profile.IconImage},
{"iconColor", &profile.IconColor},
} {
if value, ok := profileDetails.Details.Fields[s.field]; ok {
*s.receiver = value.GetStringValue()
}
}
if profileDetails != nil {
profile.Name = profileDetails.GetString(bundle.RelationKeyName)
profile.IconImage = profileDetails.GetString(bundle.RelationKeyIconImage)
}
return profile, nil

View file

@ -12,6 +12,7 @@ import (
"github.com/anyproto/anytype-heart/core/anytype/account"
"github.com/anyproto/anytype-heart/core/anytype/config"
"github.com/anyproto/anytype-heart/core/block"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/block/detailservice"
"github.com/anyproto/anytype-heart/core/domain/objectorigin"
"github.com/anyproto/anytype-heart/pb"
@ -19,7 +20,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/core"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
func (s *Service) AccountCreate(ctx context.Context, req *pb.RpcAccountCreateRequest) (*model.Account, error) {
@ -115,17 +115,17 @@ func (s *Service) setAccountAndProfileDetails(ctx context.Context, req *pb.RpcAc
newAcc.Info.AccountSpaceId = spaceService.FirstCreatedSpaceId()
bs := s.app.MustComponent(block.CName).(*block.Service)
commonDetails := []*model.Detail{
commonDetails := []domain.Detail{
{
Key: bundle.RelationKeyName.String(),
Value: pbtypes.String(req.Name),
Key: bundle.RelationKeyName,
Value: domain.String(req.Name),
},
{
Key: bundle.RelationKeyIconOption.String(),
Value: pbtypes.Int64(req.Icon),
Key: bundle.RelationKeyIconOption,
Value: domain.Int64(req.Icon),
},
}
profileDetails := make([]*model.Detail, 0)
profileDetails := make([]domain.Detail, 0)
profileDetails = append(profileDetails, commonDetails...)
if req.GetAvatarLocalPath() != "" {
@ -140,9 +140,9 @@ func (s *Service) setAccountAndProfileDetails(ctx context.Context, req *pb.RpcAc
if err != nil {
log.Warnf("can't add avatar: %v", err)
} else {
profileDetails = append(profileDetails, &model.Detail{
Key: bundle.RelationKeyIconImage.String(),
Value: pbtypes.String(hash),
profileDetails = append(profileDetails, domain.Detail{
Key: bundle.RelationKeyIconImage,
Value: domain.String(hash),
})
}
}

View file

@ -17,17 +17,16 @@ import (
"github.com/anyproto/anytype-heart/core/anytype/account"
"github.com/anyproto/anytype-heart/core/anytype/config"
"github.com/anyproto/anytype-heart/core/block/detailservice"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/metrics"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/core"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/util/anyerror"
"github.com/anyproto/anytype-heart/util/builtinobjects"
"github.com/anyproto/anytype-heart/util/constant"
"github.com/anyproto/anytype-heart/util/metricsid"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
var (
@ -188,25 +187,25 @@ func (s *Service) setDetails(profile *pb.Profile, icon int64) error {
return nil
}
func buildDetails(profile *pb.Profile, icon int64) (profileDetails []*model.Detail, accountDetails []*model.Detail) {
profileDetails = []*model.Detail{{
Key: bundle.RelationKeyName.String(),
Value: pbtypes.String(profile.Name),
func buildDetails(profile *pb.Profile, icon int64) (profileDetails []domain.Detail, accountDetails []domain.Detail) {
profileDetails = []domain.Detail{{
Key: bundle.RelationKeyName,
Value: domain.String(profile.Name),
}}
if profile.Avatar == "" {
profileDetails = append(profileDetails, &model.Detail{
Key: bundle.RelationKeyIconOption.String(),
Value: pbtypes.Int64(icon),
profileDetails = append(profileDetails, domain.Detail{
Key: bundle.RelationKeyIconOption,
Value: domain.Int64(icon),
})
} else {
profileDetails = append(profileDetails, &model.Detail{
Key: bundle.RelationKeyIconImage.String(),
Value: pbtypes.String(profile.Avatar),
profileDetails = append(profileDetails, domain.Detail{
Key: bundle.RelationKeyIconImage,
Value: domain.String(profile.Avatar),
})
}
accountDetails = []*model.Detail{{
Key: bundle.RelationKeyIconOption.String(),
Value: pbtypes.Int64(icon),
accountDetails = []domain.Detail{{
Key: bundle.RelationKeyIconOption,
Value: domain.Int64(icon),
}}
return
}

View file

@ -3,6 +3,7 @@ package application
import (
"errors"
"github.com/anyproto/anytype-heart/core/event"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/core"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
@ -18,20 +19,13 @@ func (s *Service) AccountRecover() error {
return errors.Join(ErrBadInput, err)
}
event := &pb.Event{
Messages: []*pb.EventMessage{
{
Value: &pb.EventMessageValueOfAccountShow{
AccountShow: &pb.EventAccountShow{
Account: &model.Account{
Id: res.Identity.GetPublic().Account(),
},
},
},
s.eventSender.Broadcast(event.NewEventSingleMessage("", &pb.EventMessageValueOfAccountShow{
AccountShow: &pb.EventAccountShow{
Account: &model.Account{
Id: res.Identity.GetPublic().Account(),
},
},
}
s.eventSender.Broadcast(event)
}))
return nil
}

View file

@ -5,6 +5,7 @@ import (
"fmt"
"time"
"github.com/anyproto/anytype-heart/core/event"
"github.com/anyproto/anytype-heart/core/session"
walletComp "github.com/anyproto/anytype-heart/core/wallet"
"github.com/anyproto/anytype-heart/pb"
@ -73,18 +74,12 @@ func (s *Service) LinkLocalStartNewChallenge(clientInfo *pb.EventAccountLinkChal
if err != nil {
return "", err
}
s.eventSender.Broadcast(&pb.Event{
Messages: []*pb.EventMessage{
{
Value: &pb.EventMessageValueOfAccountLinkChallenge{
AccountLinkChallenge: &pb.EventAccountLinkChallenge{
Challenge: value,
ClientInfo: clientInfo,
},
},
},
s.eventSender.Broadcast(event.NewEventSingleMessage("", &pb.EventMessageValueOfAccountLinkChallenge{
AccountLinkChallenge: &pb.EventAccountLinkChallenge{
Challenge: value,
ClientInfo: clientInfo,
},
})
}))
return id, nil
}

View file

@ -57,16 +57,16 @@ func (mw *Middleware) BlockLinkCreateWithObject(cctx context.Context, req *pb.Rp
}
var (
id, targetId string
objectDetails *types.Struct
objectDetails *domain.Details
)
err := mw.doBlockService(func(bs *block.Service) (err error) {
id, targetId, objectDetails, err = bs.CreateLinkToTheNewObject(cctx, ctx, req)
return
})
if err != nil {
return response(pb.RpcBlockLinkCreateWithObjectResponseError_UNKNOWN_ERROR, "", "", objectDetails, err)
return response(pb.RpcBlockLinkCreateWithObjectResponseError_UNKNOWN_ERROR, "", "", nil, err)
}
return response(pb.RpcBlockLinkCreateWithObjectResponseError_NULL, id, targetId, objectDetails, nil)
return response(pb.RpcBlockLinkCreateWithObjectResponseError_NULL, id, targetId, objectDetails.ToProto(), nil)
}
func (mw *Middleware) ObjectOpen(cctx context.Context, req *pb.RpcObjectOpenRequest) *pb.RpcObjectOpenResponse {

View file

@ -9,13 +9,13 @@ import (
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/app/ocache"
"github.com/cheggaaa/mb"
"github.com/gogo/protobuf/types"
"github.com/samber/lo"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/object/idresolver"
"github.com/anyproto/anytype-heart/core/block/source"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
@ -24,7 +24,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/threads"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/util/dateutil"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)
@ -218,11 +217,11 @@ func (w *watcher) updateBackLinksInObject(id string, backlinksUpdate *backLinksU
}
spaceDerivedIds := spc.DerivedIDs()
updateBacklinks := func(current *types.Struct, backlinksChange *backLinksUpdate) (*types.Struct, bool, error) {
if current == nil || current.Fields == nil {
updateBacklinks := func(current *domain.Details, backlinksChange *backLinksUpdate) (*domain.Details, bool, error) {
if current == nil {
return nil, false, nil
}
backlinks := pbtypes.GetStringList(current, bundle.RelationKeyBacklinks.String())
backlinks := current.GetStringList(bundle.RelationKeyBacklinks)
for _, removed := range backlinksChange.removed {
backlinks = slice.Remove(backlinks, removed)
@ -239,14 +238,14 @@ func (w *watcher) updateBackLinksInObject(id string, backlinksUpdate *backLinksU
return shouldIndexBacklinks(spaceDerivedIds, s)
})
current.Fields[bundle.RelationKeyBacklinks.String()] = pbtypes.StringList(backlinks)
current.SetStringList(bundle.RelationKeyBacklinks, backlinks)
return current, true, nil
}
if shouldIndexBacklinks(spaceDerivedIds, id) {
// filter-out backlinks in system objects
err = spc.DoLockedIfNotExists(id, func() error {
return w.store.SpaceIndex(spaceId).ModifyObjectDetails(id, func(details *types.Struct) (*types.Struct, bool, error) {
return w.store.SpaceIndex(spaceId).ModifyObjectDetails(id, func(details *domain.Details) (*domain.Details, bool, error) {
return updateBacklinks(details, backlinksUpdate)
})
})

View file

@ -11,13 +11,13 @@ import (
"github.com/stretchr/testify/require"
"github.com/anyproto/anytype-heart/core/block/object/idresolver/mock_idresolver"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/threads"
"github.com/anyproto/anytype-heart/space/clientspace/mock_clientspace"
"github.com/anyproto/anytype-heart/space/mock_space"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
const spaceId = "spc1"
@ -132,13 +132,13 @@ func TestWatcher_updateAccumulatedBacklinks(t *testing.T) {
f.resolver.EXPECT().ResolveSpaceID(mock.Anything).Return(spaceId, nil)
f.store.AddObjects(t, spaceId, []spaceindex.TestObject{{
bundle.RelationKeyId: pbtypes.String("obj1"),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyBacklinks: pbtypes.StringList([]string{"obj4", "obj5", "obj6"}),
bundle.RelationKeyId: domain.String("obj1"),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyBacklinks: domain.StringList([]string{"obj4", "obj5", "obj6"}),
}, {
bundle.RelationKeyId: pbtypes.String("obj3"),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyBacklinks: pbtypes.StringList([]string{"obj1", "obj2", "obj4"}),
bundle.RelationKeyId: domain.String("obj3"),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyBacklinks: domain.StringList([]string{"obj1", "obj2", "obj4"}),
}})
spc := mock_clientspace.NewMockSpace(t)
@ -174,9 +174,9 @@ func TestWatcher_updateAccumulatedBacklinks(t *testing.T) {
// then
details, err := f.store.SpaceIndex(spaceId).GetDetails("obj1")
require.NoError(t, err)
assert.Equal(t, []string{"obj6", "obj2", "obj3"}, pbtypes.GetStringList(details.Details, bundle.RelationKeyBacklinks.String()))
assert.Equal(t, []string{"obj6", "obj2", "obj3"}, details.GetStringList(bundle.RelationKeyBacklinks))
details, err = f.store.SpaceIndex(spaceId).GetDetails("obj3")
require.NoError(t, err)
assert.Equal(t, []string{"obj2"}, pbtypes.GetStringList(details.Details, bundle.RelationKeyBacklinks.String()))
assert.Equal(t, []string{"obj2"}, details.GetStringList(bundle.RelationKeyBacklinks))
})
}

View file

@ -14,7 +14,6 @@ import (
"github.com/anyproto/any-sync/app"
"github.com/globalsign/mgo/bson"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/import/markdown/anymark"
@ -31,7 +30,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/util/linkpreview"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/uri"
)
@ -41,8 +39,8 @@ const CName = "bookmark"
type ContentFuture func() *bookmark.ObjectContent
type Service interface {
CreateObjectAndFetch(ctx context.Context, spaceId string, details *types.Struct) (objectID string, newDetails *types.Struct, err error)
CreateBookmarkObject(ctx context.Context, spaceId string, details *types.Struct, getContent ContentFuture) (objectId string, newDetails *types.Struct, err error)
CreateObjectAndFetch(ctx context.Context, spaceId string, details *domain.Details) (objectID string, newDetails *domain.Details, err error)
CreateBookmarkObject(ctx context.Context, spaceId string, details *domain.Details, getContent ContentFuture) (objectId string, newDetails *domain.Details, err error)
UpdateObject(objectId string, getContent *bookmark.ObjectContent) error
// TODO Maybe Fetch and FetchBookmarkContent do the same thing differently?
FetchAsync(spaceID string, blockID string, params bookmark.FetchParams)
@ -53,11 +51,11 @@ type Service interface {
}
type ObjectCreator interface {
CreateSmartBlockFromState(ctx context.Context, spaceID string, objectTypeKeys []domain.TypeKey, createState *state.State) (id string, newDetails *types.Struct, err error)
CreateSmartBlockFromState(ctx context.Context, spaceID string, objectTypeKeys []domain.TypeKey, createState *state.State) (id string, newDetails *domain.Details, err error)
}
type DetailsSetter interface {
SetDetails(ctx session.Context, objectId string, details []*model.Detail) (err error)
SetDetails(ctx session.Context, objectId string, details []domain.Detail) (err error)
}
type service struct {
@ -92,9 +90,9 @@ func (s *service) Name() (name string) {
var log = logging.Logger("anytype-mw-bookmark")
func (s *service) CreateObjectAndFetch(
ctx context.Context, spaceId string, details *types.Struct,
) (objectID string, newDetails *types.Struct, err error) {
source := pbtypes.GetString(details, bundle.RelationKeySource.String())
ctx context.Context, spaceId string, details *domain.Details,
) (objectID string, newDetails *domain.Details, err error) {
source := details.GetString(bundle.RelationKeySource)
var res ContentFuture
if source != "" {
u, err := uri.NormalizeURI(source)
@ -111,9 +109,9 @@ func (s *service) CreateObjectAndFetch(
}
func (s *service) CreateBookmarkObject(
ctx context.Context, spaceID string, details *types.Struct, getContent ContentFuture,
) (objectId string, objectDetails *types.Struct, err error) {
if details == nil || details.Fields == nil {
ctx context.Context, spaceID string, details *domain.Details, getContent ContentFuture,
) (objectId string, objectDetails *domain.Details, err error) {
if details == nil {
return "", nil, fmt.Errorf("empty details")
}
@ -125,25 +123,25 @@ func (s *service) CreateBookmarkObject(
if err != nil {
return "", nil, fmt.Errorf("get bookmark type id: %w", err)
}
url := pbtypes.GetString(details, bundle.RelationKeySource.String())
url := details.GetString(bundle.RelationKeySource)
records, err := s.store.SpaceIndex(spaceID).Query(database.Query{
Sorts: []*model.BlockContentDataviewSort{
Sorts: []database.SortRequest{
{
RelationKey: bundle.RelationKeyLastModifiedDate.String(),
RelationKey: bundle.RelationKeyLastModifiedDate,
Type: model.BlockContentDataviewSort_Desc,
},
},
Filters: []*model.BlockContentDataviewFilter{
Filters: []database.FilterRequest{
{
RelationKey: bundle.RelationKeySource.String(),
RelationKey: bundle.RelationKeySource,
Condition: model.BlockContentDataviewFilter_Equal,
Value: pbtypes.String(url),
Value: domain.String(url),
},
{
RelationKey: bundle.RelationKeyType.String(),
RelationKey: bundle.RelationKeyType,
Condition: model.BlockContentDataviewFilter_Equal,
Value: pbtypes.String(typeId),
Value: domain.String(typeId),
},
},
Limit: 1,
@ -154,7 +152,7 @@ func (s *service) CreateBookmarkObject(
if len(records) > 0 {
rec := records[0]
objectId = rec.Details.Fields[bundle.RelationKeyId.String()].GetStringValue()
objectId = rec.Details.GetString(bundle.RelationKeyId)
objectDetails = rec.Details
} else {
creationState := state.NewDoc("", nil).(*state.State)
@ -183,25 +181,13 @@ func (s *service) CreateBookmarkObject(
return objectId, objectDetails, nil
}
func detailsFromContent(content *bookmark.ObjectContent) map[string]*types.Value {
return map[string]*types.Value{
bundle.RelationKeyName.String(): pbtypes.String(content.BookmarkContent.Title),
bundle.RelationKeyDescription.String(): pbtypes.String(content.BookmarkContent.Description),
bundle.RelationKeySource.String(): pbtypes.String(content.BookmarkContent.Url),
bundle.RelationKeyPicture.String(): pbtypes.String(content.BookmarkContent.ImageHash),
bundle.RelationKeyIconImage.String(): pbtypes.String(content.BookmarkContent.FaviconHash),
}
}
func (s *service) UpdateObject(objectId string, getContent *bookmark.ObjectContent) error {
detailsMap := detailsFromContent(getContent)
details := make([]*model.Detail, 0, len(detailsMap))
for k, v := range detailsMap {
details = append(details, &model.Detail{
Key: k,
Value: v,
})
func (s *service) UpdateObject(objectId string, content *bookmark.ObjectContent) error {
details := []domain.Detail{
{Key: bundle.RelationKeyName, Value: domain.String(content.BookmarkContent.Title)},
{Key: bundle.RelationKeyDescription, Value: domain.String(content.BookmarkContent.Description)},
{Key: bundle.RelationKeySource, Value: domain.String(content.BookmarkContent.Url)},
{Key: bundle.RelationKeyPicture, Value: domain.String(content.BookmarkContent.ImageHash)},
{Key: bundle.RelationKeyIconImage, Value: domain.String(content.BookmarkContent.FaviconHash)},
}
return s.detailsSetter.SetDetails(nil, objectId, details)

View file

@ -4,7 +4,6 @@ import (
"context"
"testing"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
@ -19,7 +18,6 @@ import (
"github.com/anyproto/anytype-heart/space/clientspace/mock_clientspace"
"github.com/anyproto/anytype-heart/space/mock_space"
"github.com/anyproto/anytype-heart/util/linkpreview/mock_linkpreview"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
const (
@ -29,7 +27,7 @@ const (
type detailsSetter struct{}
func (ds *detailsSetter) SetDetails(session.Context, string, []*model.Detail) error {
func (ds *detailsSetter) SetDetails(session.Context, string, []domain.Detail) error {
return nil
}
@ -71,9 +69,9 @@ func TestService_CreateBookmarkObject(t *testing.T) {
t.Run("new bookmark object creation", func(t *testing.T) {
// given
fx := newFixture(t)
details := &types.Struct{Fields: map[string]*types.Value{}}
details := domain.NewDetails()
fx.creator.EXPECT().CreateSmartBlockFromState(mock.Anything, mock.Anything, mock.Anything, mock.Anything).RunAndReturn(
func(_ context.Context, spcId string, keys []domain.TypeKey, state *state.State) (string, *types.Struct, error) {
func(_ context.Context, spcId string, keys []domain.TypeKey, state *state.State) (string, *domain.Details, error) {
assert.Equal(t, spaceId, spcId)
assert.Equal(t, []domain.TypeKey{bundle.TypeKeyBookmark}, keys)
assert.Equal(t, details, state.Details())
@ -93,13 +91,13 @@ func TestService_CreateBookmarkObject(t *testing.T) {
// given
fx := newFixture(t)
url := "https://url.com"
details := &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeySource.String(): pbtypes.String(url),
}}
details := domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeySource: domain.String(url),
})
fx.store.AddObjects(t, "space1", []objectstore.TestObject{{
bundle.RelationKeyId: pbtypes.String("bk"),
bundle.RelationKeySource: pbtypes.String(url),
bundle.RelationKeyType: pbtypes.String(bookmarkId),
bundle.RelationKeyId: domain.String("bk"),
bundle.RelationKeySource: domain.String(url),
bundle.RelationKeyType: domain.String(bookmarkId),
}})
// when

View file

@ -4,14 +4,13 @@ import (
"context"
"github.com/anyproto/any-sync/app"
"github.com/gogo/protobuf/types"
bookmarksvc "github.com/anyproto/anytype-heart/core/block/bookmark"
"github.com/anyproto/anytype-heart/core/block/import"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
const CName = "bookmark-importer"
@ -19,7 +18,7 @@ const CName = "bookmark-importer"
var log = logging.Logger("bookmark-importer")
type Importer interface {
ImportWeb(ctx context.Context, req *importer.ImportRequest) (string, *types.Struct, error)
ImportWeb(ctx context.Context, req *importer.ImportRequest) (string, *domain.Details, error)
}
type BookmarkImporterDecorator struct {
@ -38,8 +37,8 @@ func (bd *BookmarkImporterDecorator) Init(a *app.App) (err error) {
return nil
}
func (bd *BookmarkImporterDecorator) CreateBookmarkObject(ctx context.Context, spaceID string, details *types.Struct, getContent bookmarksvc.ContentFuture) (objectId string, newDetails *types.Struct, err error) {
url := pbtypes.GetString(details, bundle.RelationKeySource.String())
func (bd *BookmarkImporterDecorator) CreateBookmarkObject(ctx context.Context, spaceID string, details *domain.Details, getContent bookmarksvc.ContentFuture) (objectId string, newDetails *domain.Details, err error) {
url := details.GetString(bundle.RelationKeySource)
if objectId, newDetails, err = bd.Importer.ImportWeb(nil, &importer.ImportRequest{
RpcObjectImportRequest: &pb.RpcObjectImportRequest{
Params: &pb.RpcObjectImportRequestParamsOfBookmarksParams{BookmarksParams: &pb.RpcObjectImportRequestBookmarksParams{Url: url}},

View file

@ -4,7 +4,6 @@ import (
"sync"
"github.com/anyproto/any-sync/app"
"github.com/gogo/protobuf/types"
"github.com/samber/lo"
"github.com/anyproto/anytype-heart/core/block/backlinks"
@ -22,7 +21,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/internalflag"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)
@ -113,7 +111,9 @@ func (s *Service) updateCollection(ctx session.Context, contextID string, modifi
lst := s.GetStoreSlice(template.CollectionStoreKey)
lst = modifier(lst)
s.UpdateStoreSlice(template.CollectionStoreKey, lst)
internalflag.Set{}.AddToState(s)
// TODO why we're adding empty list of flags?
flags := internalflag.Set{}
flags.AddToState(s)
return nil
}, smartblock.KeepInternalFlags)
}
@ -199,7 +199,7 @@ func (s *Service) UnsubscribeFromCollection(collectionID string, subscriptionID
}
}
func (s *Service) CreateCollection(details *types.Struct, flags []*model.InternalFlag) (coresb.SmartBlockType, *types.Struct, *state.State, error) {
func (s *Service) CreateCollection(details *domain.Details, flags []*model.InternalFlag) (coresb.SmartBlockType, *domain.Details, *state.State, error) {
details = internalflag.PutToDetails(details, flags)
newState := state.NewDoc("", nil).NewState().SetDetails(details)
@ -228,7 +228,7 @@ func (s *Service) setDefaultObjectTypeToViews(spaceId string, st *state.State) {
return
}
setOfValue := pbtypes.GetStringList(st.ParentState().Details(), bundle.RelationKeySetOf.String())
setOfValue := st.ParentState().Details().GetStringList(bundle.RelationKeySetOf)
if len(setOfValue) == 0 {
return
}

View file

@ -21,7 +21,6 @@ import (
coresb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"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 collectionID = "collectionID"
@ -163,7 +162,7 @@ func TestSetObjectTypeToViews(t *testing.T) {
Views: []*model.BlockContentDataviewView{{Id: viewID1}, {Id: viewID2}},
}},
}))
parent.SetDetail(bundle.RelationKeySetOf.String(), pbtypes.StringList([]string{setOf}))
parent.SetDetail(bundle.RelationKeySetOf, domain.StringList([]string{setOf}))
return parent.NewState()
}
@ -204,8 +203,8 @@ func TestSetObjectTypeToViews(t *testing.T) {
s := newFixture(t)
s.objectStore.AddObjects(t, "space1", []objectstore.TestObject{
{
bundle.RelationKeyId: pbtypes.String(setOfValue),
bundle.RelationKeyUniqueKey: pbtypes.String(domain.MustUniqueKey(testCase.sbType, testCase.key).Marshal()),
bundle.RelationKeyId: domain.String(setOfValue),
bundle.RelationKeyUniqueKey: domain.String(domain.MustUniqueKey(testCase.sbType, testCase.key).Marshal()),
},
})

View file

@ -5,8 +5,6 @@ import (
"errors"
"fmt"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/cache"
"github.com/anyproto/anytype-heart/core/block/editor/basic"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
@ -17,7 +15,6 @@ import (
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
func (s *Service) ObjectDuplicate(ctx context.Context, id string) (objectID string, err error) {
@ -32,7 +29,7 @@ func (s *Service) ObjectDuplicate(ctx context.Context, id string) (objectID stri
}
st = b.NewState().Copy()
st.SetLocalDetails(nil)
st.SetDetail(bundle.RelationKeySourceObject.String(), pbtypes.String(id))
st.SetDetail(bundle.RelationKeySourceObject, domain.String(id))
return nil
}); err != nil {
return
@ -57,11 +54,11 @@ func (s *Service) CreateWorkspace(ctx context.Context, req *pb.RpcWorkspaceCreat
predefinedObjectIDs := newSpace.DerivedIDs()
err = cache.Do(s, predefinedObjectIDs.Workspace, func(b basic.DetailsSettable) error {
details := make([]*model.Detail, 0, len(req.Details.GetFields()))
details := make([]domain.Detail, 0, len(req.Details.GetFields()))
for k, v := range req.Details.GetFields() {
details = append(details, &model.Detail{
Key: k,
Value: v,
details = append(details, domain.Detail{
Key: domain.RelationKey(k),
Value: domain.ValueFromProto(v),
})
}
return b.SetDetails(nil, details, true)
@ -81,7 +78,7 @@ func (s *Service) CreateLinkToTheNewObject(
ctx context.Context,
sctx session.Context,
req *pb.RpcBlockLinkCreateWithObjectRequest,
) (linkID string, objectId string, objectDetails *types.Struct, err error) {
) (linkID string, objectId string, objectDetails *domain.Details, err error) {
if req.ContextId == req.TemplateId && req.ContextId != "" {
err = fmt.Errorf("unable to create link to template from this template")
return
@ -93,7 +90,7 @@ func (s *Service) CreateLinkToTheNewObject(
}
createReq := objectcreator.CreateObjectRequest{
Details: req.Details,
Details: domain.NewDetailsFromProto(req.Details),
InternalFlags: req.InternalFlags,
ObjectTypeKey: objectTypeKey,
TemplateId: req.TemplateId,
@ -141,7 +138,7 @@ func (s *Service) CreateLinkToTheNewObject(
func (s *Service) ObjectToSet(id string, source []string) error {
return cache.DoState(s, id, func(st *state.State, b basic.CommonOperations) error {
st.SetDetail(bundle.RelationKeySetOf.String(), pbtypes.StringList(source))
st.SetDetail(bundle.RelationKeySetOf, domain.StringList(source))
return b.SetObjectTypesInState(st, []domain.TypeKey{bundle.TypeKeySet}, true)
})
}

View file

@ -128,7 +128,7 @@ func (s *Service) getDebugObject(id string) (debugObject, error) {
st := sb.NewState()
root := blockbuilder.BuildAST(st.Blocks())
marshaller := jsonpb.Marshaler{}
detailsRaw, err := marshaller.MarshalToString(st.CombinedDetails())
detailsRaw, err := marshaller.MarshalToString(st.CombinedDetails().ToProto())
if err != nil {
return fmt.Errorf("marshal details: %w", err)
}

View file

@ -17,7 +17,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/database"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/clientspace"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
func (s *Service) DeleteObjectByFullID(id domain.FullID) error {
@ -56,7 +55,7 @@ func (s *Service) DeleteObjectByFullID(id domain.FullID) error {
if err != nil {
return err
}
sendOnRemoveEvent(s.eventSender, id.ObjectID)
s.sendOnRemoveEvent(id.SpaceID, id.ObjectID)
// Remove from cache
err = spc.Remove(context.Background(), id.ObjectID)
if err != nil {
@ -72,9 +71,9 @@ func (s *Service) deleteDerivedObject(id domain.FullID, spc clientspace.Space) (
)
err = spc.Do(id.ObjectID, func(b smartblock.SmartBlock) error {
st := b.NewState()
st.SetDetailAndBundledRelation(bundle.RelationKeyIsUninstalled, pbtypes.Bool(true))
st.SetDetailAndBundledRelation(bundle.RelationKeyIsUninstalled, domain.Bool(true))
if sbType == coresb.SmartBlockTypeRelation {
relationKey = pbtypes.GetString(st.Details(), bundle.RelationKeyRelationKey.String())
relationKey = st.Details().GetString(bundle.RelationKeyRelationKey)
}
return b.Apply(st)
})
@ -96,16 +95,16 @@ func (s *Service) deleteDerivedObject(id domain.FullID, spc clientspace.Space) (
func (s *Service) deleteRelationOptions(spaceId string, relationKey string) error {
relationOptions, _, err := s.objectStore.SpaceIndex(spaceId).QueryObjectIds(database.Query{
Filters: []*model.BlockContentDataviewFilter{
Filters: []database.FilterRequest{
{
RelationKey: bundle.RelationKeyLayout.String(),
RelationKey: bundle.RelationKeyLayout,
Condition: model.BlockContentDataviewFilter_Equal,
Value: pbtypes.Int64(int64(model.ObjectType_relationOption)),
Value: domain.Int64(model.ObjectType_relationOption),
},
{
RelationKey: bundle.RelationKeyRelationKey.String(),
RelationKey: bundle.RelationKeyRelationKey,
Condition: model.BlockContentDataviewFilter_Equal,
Value: pbtypes.String(relationKey),
Value: domain.String(relationKey),
},
},
})
@ -133,7 +132,7 @@ func (s *Service) OnDelete(id domain.FullID, workspaceRemove func() error) error
err := s.DoFullId(id, func(b smartblock.SmartBlock) error {
b.ObjectCloseAllSessions()
st := b.NewState()
isFavorite := pbtypes.GetBool(st.LocalDetails(), bundle.RelationKeyIsFavorite.String())
isFavorite := st.LocalDetails().GetBool(bundle.RelationKeyIsFavorite)
if err := s.detailsService.SetIsFavorite(id.ObjectID, isFavorite, false); err != nil {
log.With("objectId", id).Errorf("failed to favorite object: %v", err)
}
@ -153,16 +152,10 @@ func (s *Service) OnDelete(id domain.FullID, workspaceRemove func() error) error
return nil
}
func sendOnRemoveEvent(eventSender event.Sender, ids ...string) {
eventSender.Broadcast(&pb.Event{
Messages: []*pb.EventMessage{
{
Value: &pb.EventMessageValueOfObjectRemove{
ObjectRemove: &pb.EventObjectRemove{
Ids: ids,
},
},
},
func (s *Service) sendOnRemoveEvent(spaceId string, id string) {
s.eventSender.Broadcast(event.NewEventSingleMessage(spaceId, &pb.EventMessageValueOfObjectRemove{
ObjectRemove: &pb.EventObjectRemove{
Ids: []string{id},
},
})
}))
}

View file

@ -3,44 +3,43 @@ package detailservice
import (
"testing"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/core/domain"
)
func newStruct() *types.Struct {
return &types.Struct{Fields: map[string]*types.Value{
"tag": pbtypes.StringList([]string{"red", "black"}),
"author": pbtypes.String("William Shakespeare"),
"haters": pbtypes.StringList([]string{}),
"year": pbtypes.Int64(1564),
"numbers": pbtypes.IntList(8, 13, 21, 34),
}}
func newStruct() *domain.Details {
return domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
"tag": domain.StringList([]string{"red", "black"}),
"author": domain.String("William Shakespeare"),
"haters": domain.StringList([]string{}),
"year": domain.Int64(1564),
"numbers": domain.Int64List([]int64{8, 13, 21, 34}),
})
}
func TestAddValueToListDetail(t *testing.T) {
for _, tc := range []struct {
name string
key string
s *types.Struct
toAdd *types.Value
expected *types.Value
key domain.RelationKey
s *domain.Details
toAdd domain.Value
expected domain.Value
}{
{"string list + string list", "tag", newStruct(), pbtypes.StringList([]string{"blue", "green"}), pbtypes.StringList([]string{"red", "black", "blue", "green"})},
{"string list + string list (intersect)", "tag", newStruct(), pbtypes.StringList([]string{"blue", "black"}), pbtypes.StringList([]string{"red", "black", "blue"})},
{"string + string list", "author", newStruct(), pbtypes.StringList([]string{"Victor Hugo"}), pbtypes.StringList([]string{"William Shakespeare", "Victor Hugo"})},
{"string list + string", "tag", newStruct(), pbtypes.String("orange"), pbtypes.StringList([]string{"red", "black", "orange"})},
{"int list + int list", "numbers", newStruct(), pbtypes.IntList(55, 89), pbtypes.IntList(8, 13, 21, 34, 55, 89)},
{"int list + int list (intersect)", "numbers", newStruct(), pbtypes.IntList(13, 8, 55), pbtypes.IntList(8, 13, 21, 34, 55)},
{"int + int list", "year", newStruct(), pbtypes.IntList(1666, 2025), pbtypes.IntList(1564, 1666, 2025)},
{"int list + int", "numbers", newStruct(), pbtypes.Int64(55), pbtypes.IntList(8, 13, 21, 34, 55)},
{"string list + empty", "haters", newStruct(), pbtypes.StringList([]string{"Tomas River", "Leo Tolstoy"}), pbtypes.StringList([]string{"Tomas River", "Leo Tolstoy"})},
{"string list + no such key", "plays", newStruct(), pbtypes.StringList([]string{"Falstaff", "Romeo and Juliet", "Macbeth"}), pbtypes.StringList([]string{"Falstaff", "Romeo and Juliet", "Macbeth"})},
{"string list + string list", "tag", newStruct(), domain.StringList([]string{"blue", "green"}), domain.StringList([]string{"red", "black", "blue", "green"})},
{"string list + string list (intersect)", "tag", newStruct(), domain.StringList([]string{"blue", "black"}), domain.StringList([]string{"red", "black", "blue"})},
{"string + string list", "author", newStruct(), domain.StringList([]string{"Victor Hugo"}), domain.StringList([]string{"William Shakespeare", "Victor Hugo"})},
{"string list + string", "tag", newStruct(), domain.String("orange"), domain.StringList([]string{"red", "black", "orange"})},
{"int list + int list", "numbers", newStruct(), domain.Int64List([]int64{55, 89}), domain.Int64List([]int64{8, 13, 21, 34, 55, 89})},
{"int list + int list (intersect)", "numbers", newStruct(), domain.Int64List([]int64{13, 8, 55}), domain.Int64List([]int64{8, 13, 21, 34, 55})},
{"int + int list", "year", newStruct(), domain.Int64List([]int64{1666, 2025}), domain.Int64List([]int64{1564, 1666, 2025})},
{"int list + int", "numbers", newStruct(), domain.Int64(55), domain.Int64List([]int64{8, 13, 21, 34, 55})},
{"string list + empty", "haters", newStruct(), domain.StringList([]string{"Tomas River", "Leo Tolstoy"}), domain.StringList([]string{"Tomas River", "Leo Tolstoy"})},
{"string list + no such key", "plays", newStruct(), domain.StringList([]string{"Falstaff", "Romeo and Juliet", "Macbeth"}), domain.StringList([]string{"Falstaff", "Romeo and Juliet", "Macbeth"})},
} {
t.Run(tc.name, func(t *testing.T) {
addValueToListDetail(tc.s, tc.key, tc.toAdd)
assert.True(t, pbtypes.Get(tc.s, tc.key).Equal(tc.expected))
assert.True(t, tc.s.Get(tc.key).Equal(tc.expected))
})
}
}
@ -48,24 +47,23 @@ func TestAddValueToListDetail(t *testing.T) {
func TestRemoveValueFromListDetail(t *testing.T) {
for _, tc := range []struct {
name string
key string
s *types.Struct
toRemove *types.Value
expected *types.Value
key domain.RelationKey
s *domain.Details
toRemove domain.Value
expected domain.Value
}{
{"string list - string list", "tag", newStruct(), pbtypes.StringList([]string{"red", "black"}), nil},
{"string list - string list (some are not presented)", "tag", newStruct(), pbtypes.StringList([]string{"blue", "black"}), pbtypes.StringList([]string{"red"})},
{"string list - string", "tag", newStruct(), pbtypes.String("red"), pbtypes.StringList([]string{"black"})},
{"string - string list", "author", newStruct(), pbtypes.StringList([]string{"William Shakespeare"}), pbtypes.StringList([]string{})},
{"int list - int list", "numbers", newStruct(), pbtypes.IntList(13, 34), pbtypes.IntList(8, 21)},
{"int list - int list (some are not presented)", "numbers", newStruct(), pbtypes.IntList(2020, 5), pbtypes.IntList(8, 13, 21, 34)},
{"int - int list", "year", newStruct(), pbtypes.IntList(1380, 1564), pbtypes.IntList()},
{"int list - int", "numbers", newStruct(), pbtypes.Int64(21), pbtypes.IntList(8, 13, 34)},
{"empty - string list", "haters", newStruct(), pbtypes.StringList([]string{"Tomas River", "Leo Tolstoy"}), pbtypes.StringList([]string{})},
{"string list - string list", "tag", newStruct(), domain.StringList([]string{"red", "black"}), domain.Invalid()},
{"string list - string list (some are not presented)", "tag", newStruct(), domain.StringList([]string{"blue", "black"}), domain.StringList([]string{"red"})},
{"string list - string", "tag", newStruct(), domain.String("red"), domain.StringList([]string{"black"})},
{"string - string list", "author", newStruct(), domain.StringList([]string{"William Shakespeare"}), domain.StringList([]string{})},
{"int list - int list", "numbers", newStruct(), domain.Int64List([]int64{13, 34}), domain.Int64List([]int64{8, 21})},
{"int list - int list (some are not presented)", "numbers", newStruct(), domain.Int64List([]int64{2020, 5}), domain.Int64List([]int64{8, 13, 21, 34})},
{"int - int list", "year", newStruct(), domain.Int64List([]int64{1380, 1564}), domain.Invalid()},
{"int list - int", "numbers", newStruct(), domain.Int64(21), domain.Int64List([]int64{8, 13, 34})},
{"empty - string list", "haters", newStruct(), domain.StringList([]string{"Tomas River", "Leo Tolstoy"}), domain.StringList([]string{})},
} {
t.Run(tc.name, func(t *testing.T) {
removeValueFromListDetail(tc.s, tc.key, tc.toRemove)
assert.True(t, pbtypes.Get(tc.s, tc.key).Equal(tc.expected))
})
}
}

View file

@ -11,13 +11,9 @@ import (
mock "github.com/stretchr/testify/mock"
model "github.com/anyproto/anytype-heart/pkg/lib/pb/model"
pb "github.com/anyproto/anytype-heart/pb"
session "github.com/anyproto/anytype-heart/core/session"
types "github.com/gogo/protobuf/types"
)
// MockService is an autogenerated mock type for the Service type
@ -80,7 +76,7 @@ func (_c *MockService_Init_Call) RunAndReturn(run func(*app.App) error) *MockSer
}
// ListRelationsWithValue provides a mock function with given fields: spaceId, value
func (_m *MockService) ListRelationsWithValue(spaceId string, value *types.Value) ([]*pb.RpcRelationListWithValueResponseResponseItem, error) {
func (_m *MockService) ListRelationsWithValue(spaceId string, value domain.Value) ([]*pb.RpcRelationListWithValueResponseResponseItem, error) {
ret := _m.Called(spaceId, value)
if len(ret) == 0 {
@ -89,10 +85,10 @@ func (_m *MockService) ListRelationsWithValue(spaceId string, value *types.Value
var r0 []*pb.RpcRelationListWithValueResponseResponseItem
var r1 error
if rf, ok := ret.Get(0).(func(string, *types.Value) ([]*pb.RpcRelationListWithValueResponseResponseItem, error)); ok {
if rf, ok := ret.Get(0).(func(string, domain.Value) ([]*pb.RpcRelationListWithValueResponseResponseItem, error)); ok {
return rf(spaceId, value)
}
if rf, ok := ret.Get(0).(func(string, *types.Value) []*pb.RpcRelationListWithValueResponseResponseItem); ok {
if rf, ok := ret.Get(0).(func(string, domain.Value) []*pb.RpcRelationListWithValueResponseResponseItem); ok {
r0 = rf(spaceId, value)
} else {
if ret.Get(0) != nil {
@ -100,7 +96,7 @@ func (_m *MockService) ListRelationsWithValue(spaceId string, value *types.Value
}
}
if rf, ok := ret.Get(1).(func(string, *types.Value) error); ok {
if rf, ok := ret.Get(1).(func(string, domain.Value) error); ok {
r1 = rf(spaceId, value)
} else {
r1 = ret.Error(1)
@ -116,14 +112,14 @@ type MockService_ListRelationsWithValue_Call struct {
// ListRelationsWithValue is a helper method to define mock.On call
// - spaceId string
// - value *types.Value
// - value domain.Value
func (_e *MockService_Expecter) ListRelationsWithValue(spaceId interface{}, value interface{}) *MockService_ListRelationsWithValue_Call {
return &MockService_ListRelationsWithValue_Call{Call: _e.mock.On("ListRelationsWithValue", spaceId, value)}
}
func (_c *MockService_ListRelationsWithValue_Call) Run(run func(spaceId string, value *types.Value)) *MockService_ListRelationsWithValue_Call {
func (_c *MockService_ListRelationsWithValue_Call) Run(run func(spaceId string, value domain.Value)) *MockService_ListRelationsWithValue_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string), args[1].(*types.Value))
run(args[0].(string), args[1].(domain.Value))
})
return _c
}
@ -133,13 +129,13 @@ func (_c *MockService_ListRelationsWithValue_Call) Return(_a0 []*pb.RpcRelationL
return _c
}
func (_c *MockService_ListRelationsWithValue_Call) RunAndReturn(run func(string, *types.Value) ([]*pb.RpcRelationListWithValueResponseResponseItem, error)) *MockService_ListRelationsWithValue_Call {
func (_c *MockService_ListRelationsWithValue_Call) RunAndReturn(run func(string, domain.Value) ([]*pb.RpcRelationListWithValueResponseResponseItem, error)) *MockService_ListRelationsWithValue_Call {
_c.Call.Return(run)
return _c
}
// ModifyDetails provides a mock function with given fields: objectId, modifier
func (_m *MockService) ModifyDetails(objectId string, modifier func(*types.Struct) (*types.Struct, error)) error {
func (_m *MockService) ModifyDetails(objectId string, modifier func(*domain.Details) (*domain.Details, error)) error {
ret := _m.Called(objectId, modifier)
if len(ret) == 0 {
@ -147,7 +143,7 @@ func (_m *MockService) ModifyDetails(objectId string, modifier func(*types.Struc
}
var r0 error
if rf, ok := ret.Get(0).(func(string, func(*types.Struct) (*types.Struct, error)) error); ok {
if rf, ok := ret.Get(0).(func(string, func(*domain.Details) (*domain.Details, error)) error); ok {
r0 = rf(objectId, modifier)
} else {
r0 = ret.Error(0)
@ -163,14 +159,14 @@ type MockService_ModifyDetails_Call struct {
// ModifyDetails is a helper method to define mock.On call
// - objectId string
// - modifier func(*types.Struct)(*types.Struct , error)
// - modifier func(*domain.Details)(*domain.Details , error)
func (_e *MockService_Expecter) ModifyDetails(objectId interface{}, modifier interface{}) *MockService_ModifyDetails_Call {
return &MockService_ModifyDetails_Call{Call: _e.mock.On("ModifyDetails", objectId, modifier)}
}
func (_c *MockService_ModifyDetails_Call) Run(run func(objectId string, modifier func(*types.Struct) (*types.Struct, error))) *MockService_ModifyDetails_Call {
func (_c *MockService_ModifyDetails_Call) Run(run func(objectId string, modifier func(*domain.Details) (*domain.Details, error))) *MockService_ModifyDetails_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string), args[1].(func(*types.Struct) (*types.Struct, error)))
run(args[0].(string), args[1].(func(*domain.Details) (*domain.Details, error)))
})
return _c
}
@ -180,7 +176,7 @@ func (_c *MockService_ModifyDetails_Call) Return(_a0 error) *MockService_ModifyD
return _c
}
func (_c *MockService_ModifyDetails_Call) RunAndReturn(run func(string, func(*types.Struct) (*types.Struct, error)) error) *MockService_ModifyDetails_Call {
func (_c *MockService_ModifyDetails_Call) RunAndReturn(run func(string, func(*domain.Details) (*domain.Details, error)) error) *MockService_ModifyDetails_Call {
_c.Call.Return(run)
return _c
}
@ -373,7 +369,7 @@ func (_c *MockService_ObjectTypeRemoveRelations_Call) RunAndReturn(run func(cont
}
// SetDetails provides a mock function with given fields: ctx, objectId, details
func (_m *MockService) SetDetails(ctx session.Context, objectId string, details []*model.Detail) error {
func (_m *MockService) SetDetails(ctx session.Context, objectId string, details []domain.Detail) error {
ret := _m.Called(ctx, objectId, details)
if len(ret) == 0 {
@ -381,7 +377,7 @@ func (_m *MockService) SetDetails(ctx session.Context, objectId string, details
}
var r0 error
if rf, ok := ret.Get(0).(func(session.Context, string, []*model.Detail) error); ok {
if rf, ok := ret.Get(0).(func(session.Context, string, []domain.Detail) error); ok {
r0 = rf(ctx, objectId, details)
} else {
r0 = ret.Error(0)
@ -398,14 +394,14 @@ type MockService_SetDetails_Call struct {
// SetDetails is a helper method to define mock.On call
// - ctx session.Context
// - objectId string
// - details []*model.Detail
// - details []domain.Detail
func (_e *MockService_Expecter) SetDetails(ctx interface{}, objectId interface{}, details interface{}) *MockService_SetDetails_Call {
return &MockService_SetDetails_Call{Call: _e.mock.On("SetDetails", ctx, objectId, details)}
}
func (_c *MockService_SetDetails_Call) Run(run func(ctx session.Context, objectId string, details []*model.Detail)) *MockService_SetDetails_Call {
func (_c *MockService_SetDetails_Call) Run(run func(ctx session.Context, objectId string, details []domain.Detail)) *MockService_SetDetails_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(session.Context), args[1].(string), args[2].([]*model.Detail))
run(args[0].(session.Context), args[1].(string), args[2].([]domain.Detail))
})
return _c
}
@ -415,13 +411,13 @@ func (_c *MockService_SetDetails_Call) Return(_a0 error) *MockService_SetDetails
return _c
}
func (_c *MockService_SetDetails_Call) RunAndReturn(run func(session.Context, string, []*model.Detail) error) *MockService_SetDetails_Call {
func (_c *MockService_SetDetails_Call) RunAndReturn(run func(session.Context, string, []domain.Detail) error) *MockService_SetDetails_Call {
_c.Call.Return(run)
return _c
}
// SetDetailsAndUpdateLastUsed provides a mock function with given fields: ctx, objectId, details
func (_m *MockService) SetDetailsAndUpdateLastUsed(ctx session.Context, objectId string, details []*model.Detail) error {
func (_m *MockService) SetDetailsAndUpdateLastUsed(ctx session.Context, objectId string, details []domain.Detail) error {
ret := _m.Called(ctx, objectId, details)
if len(ret) == 0 {
@ -429,7 +425,7 @@ func (_m *MockService) SetDetailsAndUpdateLastUsed(ctx session.Context, objectId
}
var r0 error
if rf, ok := ret.Get(0).(func(session.Context, string, []*model.Detail) error); ok {
if rf, ok := ret.Get(0).(func(session.Context, string, []domain.Detail) error); ok {
r0 = rf(ctx, objectId, details)
} else {
r0 = ret.Error(0)
@ -446,14 +442,14 @@ type MockService_SetDetailsAndUpdateLastUsed_Call struct {
// SetDetailsAndUpdateLastUsed is a helper method to define mock.On call
// - ctx session.Context
// - objectId string
// - details []*model.Detail
// - details []domain.Detail
func (_e *MockService_Expecter) SetDetailsAndUpdateLastUsed(ctx interface{}, objectId interface{}, details interface{}) *MockService_SetDetailsAndUpdateLastUsed_Call {
return &MockService_SetDetailsAndUpdateLastUsed_Call{Call: _e.mock.On("SetDetailsAndUpdateLastUsed", ctx, objectId, details)}
}
func (_c *MockService_SetDetailsAndUpdateLastUsed_Call) Run(run func(ctx session.Context, objectId string, details []*model.Detail)) *MockService_SetDetailsAndUpdateLastUsed_Call {
func (_c *MockService_SetDetailsAndUpdateLastUsed_Call) Run(run func(ctx session.Context, objectId string, details []domain.Detail)) *MockService_SetDetailsAndUpdateLastUsed_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(session.Context), args[1].(string), args[2].([]*model.Detail))
run(args[0].(session.Context), args[1].(string), args[2].([]domain.Detail))
})
return _c
}
@ -463,13 +459,13 @@ func (_c *MockService_SetDetailsAndUpdateLastUsed_Call) Return(_a0 error) *MockS
return _c
}
func (_c *MockService_SetDetailsAndUpdateLastUsed_Call) RunAndReturn(run func(session.Context, string, []*model.Detail) error) *MockService_SetDetailsAndUpdateLastUsed_Call {
func (_c *MockService_SetDetailsAndUpdateLastUsed_Call) RunAndReturn(run func(session.Context, string, []domain.Detail) error) *MockService_SetDetailsAndUpdateLastUsed_Call {
_c.Call.Return(run)
return _c
}
// SetDetailsList provides a mock function with given fields: ctx, objectIds, details
func (_m *MockService) SetDetailsList(ctx session.Context, objectIds []string, details []*model.Detail) error {
func (_m *MockService) SetDetailsList(ctx session.Context, objectIds []string, details []domain.Detail) error {
ret := _m.Called(ctx, objectIds, details)
if len(ret) == 0 {
@ -477,7 +473,7 @@ func (_m *MockService) SetDetailsList(ctx session.Context, objectIds []string, d
}
var r0 error
if rf, ok := ret.Get(0).(func(session.Context, []string, []*model.Detail) error); ok {
if rf, ok := ret.Get(0).(func(session.Context, []string, []domain.Detail) error); ok {
r0 = rf(ctx, objectIds, details)
} else {
r0 = ret.Error(0)
@ -494,14 +490,14 @@ type MockService_SetDetailsList_Call struct {
// SetDetailsList is a helper method to define mock.On call
// - ctx session.Context
// - objectIds []string
// - details []*model.Detail
// - details []domain.Detail
func (_e *MockService_Expecter) SetDetailsList(ctx interface{}, objectIds interface{}, details interface{}) *MockService_SetDetailsList_Call {
return &MockService_SetDetailsList_Call{Call: _e.mock.On("SetDetailsList", ctx, objectIds, details)}
}
func (_c *MockService_SetDetailsList_Call) Run(run func(ctx session.Context, objectIds []string, details []*model.Detail)) *MockService_SetDetailsList_Call {
func (_c *MockService_SetDetailsList_Call) Run(run func(ctx session.Context, objectIds []string, details []domain.Detail)) *MockService_SetDetailsList_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(session.Context), args[1].([]string), args[2].([]*model.Detail))
run(args[0].(session.Context), args[1].([]string), args[2].([]domain.Detail))
})
return _c
}
@ -511,7 +507,7 @@ func (_c *MockService_SetDetailsList_Call) Return(_a0 error) *MockService_SetDet
return _c
}
func (_c *MockService_SetDetailsList_Call) RunAndReturn(run func(session.Context, []string, []*model.Detail) error) *MockService_SetDetailsList_Call {
func (_c *MockService_SetDetailsList_Call) RunAndReturn(run func(session.Context, []string, []domain.Detail) error) *MockService_SetDetailsList_Call {
_c.Call.Return(run)
return _c
}
@ -706,7 +702,7 @@ func (_c *MockService_SetListIsFavorite_Call) RunAndReturn(run func([]string, bo
}
// SetSpaceInfo provides a mock function with given fields: spaceId, details
func (_m *MockService) SetSpaceInfo(spaceId string, details *types.Struct) error {
func (_m *MockService) SetSpaceInfo(spaceId string, details *domain.Details) error {
ret := _m.Called(spaceId, details)
if len(ret) == 0 {
@ -714,7 +710,7 @@ func (_m *MockService) SetSpaceInfo(spaceId string, details *types.Struct) error
}
var r0 error
if rf, ok := ret.Get(0).(func(string, *types.Struct) error); ok {
if rf, ok := ret.Get(0).(func(string, *domain.Details) error); ok {
r0 = rf(spaceId, details)
} else {
r0 = ret.Error(0)
@ -730,14 +726,14 @@ type MockService_SetSpaceInfo_Call struct {
// SetSpaceInfo is a helper method to define mock.On call
// - spaceId string
// - details *types.Struct
// - details *domain.Details
func (_e *MockService_Expecter) SetSpaceInfo(spaceId interface{}, details interface{}) *MockService_SetSpaceInfo_Call {
return &MockService_SetSpaceInfo_Call{Call: _e.mock.On("SetSpaceInfo", spaceId, details)}
}
func (_c *MockService_SetSpaceInfo_Call) Run(run func(spaceId string, details *types.Struct)) *MockService_SetSpaceInfo_Call {
func (_c *MockService_SetSpaceInfo_Call) Run(run func(spaceId string, details *domain.Details)) *MockService_SetSpaceInfo_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string), args[1].(*types.Struct))
run(args[0].(string), args[1].(*domain.Details))
})
return _c
}
@ -747,7 +743,7 @@ func (_c *MockService_SetSpaceInfo_Call) Return(_a0 error) *MockService_SetSpace
return _c
}
func (_c *MockService_SetSpaceInfo_Call) RunAndReturn(run func(string, *types.Struct) error) *MockService_SetSpaceInfo_Call {
func (_c *MockService_SetSpaceInfo_Call) RunAndReturn(run func(string, *domain.Details) error) *MockService_SetSpaceInfo_Call {
_c.Call.Return(run)
return _c
}

View file

@ -8,7 +8,6 @@ import (
"strings"
"time"
"github.com/gogo/protobuf/types"
"go.uber.org/zap"
"golang.org/x/exp/maps"
@ -21,7 +20,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/database"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/dateutil"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
timeutil "github.com/anyproto/anytype-heart/util/time"
)
@ -34,7 +32,7 @@ func (s *service) ObjectTypeAddRelations(ctx context.Context, objectTypeId strin
}
return cache.Do(s.objectGetter, objectTypeId, func(b smartblock.SmartBlock) error {
st := b.NewState()
list := pbtypes.GetStringList(st.Details(), bundle.RelationKeyRecommendedRelations.String())
list := st.Details().GetStringList(bundle.RelationKeyRecommendedRelations)
for _, relKey := range relationKeys {
relId, err := b.Space().GetRelationIdByKey(ctx, relKey)
if err != nil {
@ -44,7 +42,7 @@ func (s *service) ObjectTypeAddRelations(ctx context.Context, objectTypeId strin
list = append(list, relId)
}
}
st.SetDetailAndBundledRelation(bundle.RelationKeyRecommendedRelations, pbtypes.StringList(list))
st.SetDetailAndBundledRelation(bundle.RelationKeyRecommendedRelations, domain.StringList(list))
return b.Apply(st)
})
}
@ -55,7 +53,7 @@ func (s *service) ObjectTypeRemoveRelations(ctx context.Context, objectTypeId st
}
return cache.Do(s.objectGetter, objectTypeId, func(b smartblock.SmartBlock) error {
st := b.NewState()
list := pbtypes.GetStringList(st.Details(), bundle.RelationKeyRecommendedRelations.String())
list := st.Details().GetStringList(bundle.RelationKeyRecommendedRelations)
for _, relKey := range relationKeys {
relId, err := b.Space().GetRelationIdByKey(ctx, relKey)
if err != nil {
@ -63,28 +61,30 @@ func (s *service) ObjectTypeRemoveRelations(ctx context.Context, objectTypeId st
}
list = slice.RemoveMut(list, relId)
}
st.SetDetailAndBundledRelation(bundle.RelationKeyRecommendedRelations, pbtypes.StringList(list))
st.SetDetailAndBundledRelation(bundle.RelationKeyRecommendedRelations, domain.StringList(list))
return b.Apply(st)
})
}
func (s *service) ListRelationsWithValue(spaceId string, value *types.Value) ([]*pb.RpcRelationListWithValueResponseResponseItem, error) {
func (s *service) ListRelationsWithValue(spaceId string, value domain.Value) ([]*pb.RpcRelationListWithValueResponseResponseItem, error) {
var (
countersByKeys = make(map[string]int64)
countersByKeys = make(map[domain.RelationKey]int64)
detailHandlesValue = generateFilter(value)
)
err := s.store.SpaceIndex(spaceId).QueryIterate(database.Query{Filters: nil}, func(details *types.Struct) {
for key, valueToCheck := range details.Fields {
if detailHandlesValue(valueToCheck) {
if counter, ok := countersByKeys[key]; ok {
countersByKeys[key] = counter + 1
} else {
countersByKeys[key] = 1
err := s.store.SpaceIndex(spaceId).QueryIterate(
database.Query{Filters: nil},
func(details *domain.Details) {
for key, valueToCheck := range details.Iterate() {
if detailHandlesValue(valueToCheck) {
if counter, ok := countersByKeys[key]; ok {
countersByKeys[key] = counter + 1
} else {
countersByKeys[key] = 1
}
}
}
}
})
})
if err != nil {
return nil, fmt.Errorf("failed to query objects: %w", err)
@ -92,10 +92,10 @@ func (s *service) ListRelationsWithValue(spaceId string, value *types.Value) ([]
keys := maps.Keys(countersByKeys)
sort.Slice(keys, func(i, j int) bool {
if keys[i] == bundle.RelationKeyMentions.String() {
if keys[i] == bundle.RelationKeyMentions {
return true
}
if keys[j] == bundle.RelationKeyMentions.String() {
if keys[j] == bundle.RelationKeyMentions {
return false
}
return keys[i] < keys[j]
@ -104,7 +104,7 @@ func (s *service) ListRelationsWithValue(spaceId string, value *types.Value) ([]
list := make([]*pb.RpcRelationListWithValueResponseResponseItem, len(keys))
for i, key := range keys {
list[i] = &pb.RpcRelationListWithValueResponseResponseItem{
RelationKey: key,
RelationKey: string(key),
Counter: countersByKeys[key],
}
}
@ -112,10 +112,10 @@ func (s *service) ListRelationsWithValue(spaceId string, value *types.Value) ([]
return list, nil
}
func generateFilter(value *types.Value) func(v *types.Value) bool {
equalOrHasFilter := func(v *types.Value) bool {
if list := v.GetListValue(); list != nil {
for _, element := range list.Values {
func generateFilter(value domain.Value) func(v domain.Value) bool {
equalOrHasFilter := func(v domain.Value) bool {
if list, ok := v.TryListValues(); ok {
for _, element := range list {
if element.Equal(value) {
return true
}
@ -124,7 +124,7 @@ func generateFilter(value *types.Value) func(v *types.Value) bool {
return v.Equal(value)
}
stringValue := value.GetStringValue()
stringValue := value.String()
if stringValue == "" {
return equalOrHasFilter
}
@ -158,22 +158,21 @@ func generateFilter(value *types.Value) func(v *types.Value) bool {
// - for relations with number format it checks timestamp value is between timestamps of this day midnights
// - for relations carrying string list it checks if some of the strings has day prefix, e.g.
// if _date_2023-12-12-08-30-50Z-0200 is queried, then all relations with prefix _date_2023-12-12 will be returned
return func(v *types.Value) bool {
numberValue := int64(v.GetNumberValue())
return func(v domain.Value) bool {
numberValue := v.Int64()
if numberValue >= startTimestamp && numberValue < endTimestamp {
return true
}
if list := v.GetListValue(); list != nil {
for _, element := range list.Values {
if element.Equal(value) {
return true
}
if strings.HasPrefix(element.GetStringValue(), shortId) {
return true
}
for _, element := range v.WrapToList() {
if element.Equal(value) {
return true
}
if strings.HasPrefix(element.String(), shortId) {
return true
}
}
return v.Equal(value)
}
}

View file

@ -5,7 +5,6 @@ import (
"testing"
"time"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
@ -18,16 +17,15 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/dateutil"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
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)),
bundle.RelationKeyId: domain.String(key.URL()),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyLayout: domain.Float64(float64(model.ObjectType_relation)),
bundle.RelationKeyRelationKey: domain.String(key.String()),
bundle.RelationKeyRelationFormat: domain.Int64(int64(format)),
}
}
@ -47,33 +45,33 @@ func TestService_ListRelationsWithValue(t *testing.T) {
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(now.Add(-5 * time.Minute).Unix()),
bundle.RelationKeyAddedDate: pbtypes.Int64(now.Add(-3 * time.Minute).Unix()),
bundle.RelationKeyLastModifiedDate: pbtypes.Int64(now.Add(-1 * time.Minute).Unix()),
bundle.RelationKeyIsFavorite: pbtypes.Bool(true),
"daysTillSummer": pbtypes.Int64(300),
bundle.RelationKeyLinks: pbtypes.StringList([]string{"obj2", "obj3", dateutil.NewDateObject(now.Add(-30*time.Minute), true).Id()}),
bundle.RelationKeyId: domain.String("obj1"),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyCreatedDate: domain.Int64(now.Add(-5 * time.Minute).Unix()),
bundle.RelationKeyAddedDate: domain.Int64(now.Add(-3 * time.Minute).Unix()),
bundle.RelationKeyLastModifiedDate: domain.Int64(now.Add(-1 * time.Minute).Unix()),
bundle.RelationKeyIsFavorite: domain.Bool(true),
"daysTillSummer": domain.Int64(300),
bundle.RelationKeyLinks: domain.StringList([]string{"obj2", "obj3", dateutil.NewDateObject(now.Add(-30*time.Minute), true).Id()}),
},
{
bundle.RelationKeyId: pbtypes.String("obj2"),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyName: pbtypes.String(dateutil.NewDateObject(now, true).Id()),
bundle.RelationKeyCreatedDate: pbtypes.Int64(now.Add(-24*time.Hour - 5*time.Minute).Unix()),
bundle.RelationKeyAddedDate: pbtypes.Int64(now.Add(-24*time.Hour - 3*time.Minute).Unix()),
bundle.RelationKeyLastModifiedDate: pbtypes.Int64(now.Add(-1 * time.Minute).Unix()),
bundle.RelationKeyCoverX: pbtypes.Int64(300),
bundle.RelationKeyId: domain.String("obj2"),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyName: domain.String(dateutil.NewDateObject(now, true).Id()),
bundle.RelationKeyCreatedDate: domain.Int64(now.Add(-24*time.Hour - 5*time.Minute).Unix()),
bundle.RelationKeyAddedDate: domain.Int64(now.Add(-24*time.Hour - 3*time.Minute).Unix()),
bundle.RelationKeyLastModifiedDate: domain.Int64(now.Add(-1 * time.Minute).Unix()),
bundle.RelationKeyCoverX: domain.Int64(300),
},
{
bundle.RelationKeyId: pbtypes.String("obj3"),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyIsHidden: pbtypes.Bool(true),
bundle.RelationKeyCreatedDate: pbtypes.Int64(now.Add(-3 * time.Minute).Unix()),
bundle.RelationKeyLastModifiedDate: pbtypes.Int64(now.Unix()),
bundle.RelationKeyIsFavorite: pbtypes.Bool(true),
bundle.RelationKeyCoverX: pbtypes.Int64(300),
bundle.RelationKeyMentions: pbtypes.StringList([]string{dateutil.NewDateObject(now, true).Id(), dateutil.NewDateObject(now.Add(-24*time.Hour), true).Id()}),
bundle.RelationKeyId: domain.String("obj3"),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyIsHidden: domain.Bool(true),
bundle.RelationKeyCreatedDate: domain.Int64(now.Add(-3 * time.Minute).Unix()),
bundle.RelationKeyLastModifiedDate: domain.Int64(now.Unix()),
bundle.RelationKeyIsFavorite: domain.Bool(true),
bundle.RelationKeyCoverX: domain.Int64(300),
bundle.RelationKeyMentions: domain.StringList([]string{dateutil.NewDateObject(now, true).Id(), dateutil.NewDateObject(now.Add(-24*time.Hour), true).Id()}),
},
})
@ -81,12 +79,12 @@ func TestService_ListRelationsWithValue(t *testing.T) {
for _, tc := range []struct {
name string
value *types.Value
value domain.Value
expectedList []*pb.RpcRelationListWithValueResponseResponseItem
}{
{
"date object - today",
pbtypes.String(dateutil.NewDateObject(now, true).Id()),
domain.String(dateutil.NewDateObject(now, true).Id()),
[]*pb.RpcRelationListWithValueResponseResponseItem{
{bundle.RelationKeyMentions.String(), 1},
{bundle.RelationKeyAddedDate.String(), 1},
@ -98,7 +96,7 @@ func TestService_ListRelationsWithValue(t *testing.T) {
},
{
"date object - yesterday",
pbtypes.String(dateutil.NewDateObject(now.Add(-24*time.Hour), true).Id()),
domain.String(dateutil.NewDateObject(now.Add(-24*time.Hour), true).Id()),
[]*pb.RpcRelationListWithValueResponseResponseItem{
{bundle.RelationKeyMentions.String(), 1},
{bundle.RelationKeyAddedDate.String(), 1},
@ -107,7 +105,7 @@ func TestService_ListRelationsWithValue(t *testing.T) {
},
{
"number",
pbtypes.Int64(300),
domain.Int64(300),
[]*pb.RpcRelationListWithValueResponseResponseItem{
{bundle.RelationKeyCoverX.String(), 2},
{"daysTillSummer", 1},
@ -115,7 +113,7 @@ func TestService_ListRelationsWithValue(t *testing.T) {
},
{
"bool",
pbtypes.Bool(true),
domain.Bool(true),
[]*pb.RpcRelationListWithValueResponseResponseItem{
{bundle.RelationKeyIsFavorite.String(), 2},
{bundle.RelationKeyIsHidden.String(), 1},
@ -123,7 +121,7 @@ func TestService_ListRelationsWithValue(t *testing.T) {
},
{
"string list",
pbtypes.StringList([]string{"obj2", "obj3", dateutil.NewDateObject(now.Add(-30*time.Minute), true).Id()}),
domain.StringList([]string{"obj2", "obj3", dateutil.NewDateObject(now.Add(-30*time.Minute), true).Id()}),
[]*pb.RpcRelationListWithValueResponseResponseItem{
{bundle.RelationKeyLinks.String(), 1},
},
@ -159,7 +157,7 @@ func TestService_ObjectTypeAddRelations(t *testing.T) {
// then
assert.NoError(t, err)
assert.Equal(t, []string{bundle.RelationKeyAssignee.URL(), bundle.RelationKeyDone.URL()},
pbtypes.GetStringList(sb.Details(), bundle.RelationKeyRecommendedRelations.String()))
sb.Details().GetStringList(bundle.RelationKeyRecommendedRelations))
})
t.Run("editing of bundled types is prohibited", func(t *testing.T) {
@ -183,14 +181,14 @@ func TestService_ObjectTypeRemoveRelations(t *testing.T) {
fx := newFixture(t)
sb := smarttest.New(bundle.TypeKeyTask.URL())
sb.SetSpace(fx.space)
sb.Doc.(*state.State).SetDetails(&types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyRecommendedRelations.String(): pbtypes.StringList([]string{
sb.Doc.(*state.State).SetDetails(domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyRecommendedRelations: domain.StringList([]string{
bundle.RelationKeyAssignee.URL(),
bundle.RelationKeyIsFavorite.URL(),
bundle.RelationKeyDone.URL(),
bundle.RelationKeyLinkedProjects.URL(),
}),
}})
}))
fx.getter.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, objectId string) (smartblock.SmartBlock, error) {
assert.Equal(t, bundle.TypeKeyTask.URL(), objectId)
return sb, nil
@ -207,7 +205,7 @@ func TestService_ObjectTypeRemoveRelations(t *testing.T) {
// then
assert.NoError(t, err)
assert.Equal(t, []string{bundle.RelationKeyIsFavorite.URL(), bundle.RelationKeyLinkedProjects.URL()},
pbtypes.GetStringList(sb.Details(), bundle.RelationKeyRecommendedRelations.String()))
sb.Details().GetStringList(bundle.RelationKeyRecommendedRelations))
})
t.Run("editing of bundled types is prohibited", func(t *testing.T) {

View file

@ -7,7 +7,6 @@ import (
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/app/logger"
"github.com/gogo/protobuf/types"
"github.com/samber/lo"
"go.uber.org/zap"
@ -19,7 +18,6 @@ import (
"github.com/anyproto/anytype-heart/core/session"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
@ -32,18 +30,18 @@ var log = logger.NewNamed(CName)
type Service interface {
app.Component
SetDetails(ctx session.Context, objectId string, details []*model.Detail) error
SetDetailsAndUpdateLastUsed(ctx session.Context, objectId string, details []*model.Detail) error
SetDetailsList(ctx session.Context, objectIds []string, details []*model.Detail) error
ModifyDetails(objectId string, modifier func(current *types.Struct) (*types.Struct, error)) error
SetDetails(ctx session.Context, objectId string, details []domain.Detail) error
SetDetailsAndUpdateLastUsed(ctx session.Context, objectId string, details []domain.Detail) error
SetDetailsList(ctx session.Context, objectIds []string, details []domain.Detail) error
ModifyDetails(objectId string, modifier func(current *domain.Details) (*domain.Details, error)) error
ModifyDetailsList(req *pb.RpcObjectListModifyDetailValuesRequest) error
ObjectTypeAddRelations(ctx context.Context, objectTypeId string, relationKeys []domain.RelationKey) error
ObjectTypeRemoveRelations(ctx context.Context, objectTypeId string, relationKeys []domain.RelationKey) error
ListRelationsWithValue(spaceId string, value *types.Value) ([]*pb.RpcRelationListWithValueResponseResponseItem, error)
ListRelationsWithValue(spaceId string, value domain.Value) ([]*pb.RpcRelationListWithValueResponseResponseItem, error)
SetSpaceInfo(spaceId string, details *types.Struct) error
SetSpaceInfo(spaceId string, details *domain.Details) error
SetWorkspaceDashboardId(ctx session.Context, workspaceId string, id string) (setId string, err error)
SetIsFavorite(objectId string, isFavorite, createWidget bool) error
@ -77,19 +75,19 @@ func (s *service) Name() string {
return CName
}
func (s *service) SetDetails(ctx session.Context, objectId string, details []*model.Detail) (err error) {
func (s *service) SetDetails(ctx session.Context, objectId string, details []domain.Detail) (err error) {
return cache.Do(s.objectGetter, objectId, func(b basic.DetailsSettable) error {
return b.SetDetails(ctx, details, true)
})
}
func (s *service) SetDetailsAndUpdateLastUsed(ctx session.Context, objectId string, details []*model.Detail) (err error) {
func (s *service) SetDetailsAndUpdateLastUsed(ctx session.Context, objectId string, details []domain.Detail) (err error) {
return cache.Do(s.objectGetter, objectId, func(b basic.DetailsSettable) error {
return b.SetDetailsAndUpdateLastUsed(ctx, details, true)
})
}
func (s *service) SetDetailsList(ctx session.Context, objectIds []string, details []*model.Detail) (err error) {
func (s *service) SetDetailsList(ctx session.Context, objectIds []string, details []domain.Detail) (err error) {
var (
resultError error
anySucceed bool
@ -116,13 +114,13 @@ func (s *service) SetDetailsList(ctx session.Context, objectIds []string, detail
}
// ModifyDetails performs details get and update under the sb lock to make sure no modifications are done in the middle
func (s *service) ModifyDetails(objectId string, modifier func(current *types.Struct) (*types.Struct, error)) (err error) {
func (s *service) ModifyDetails(objectId string, modifier func(current *domain.Details) (*domain.Details, error)) (err error) {
return cache.Do(s.objectGetter, objectId, func(du basic.DetailsUpdatable) error {
return du.UpdateDetails(modifier)
})
}
func (s *service) ModifyDetailsAndUpdateLastUsed(objectId string, modifier func(current *types.Struct) (*types.Struct, error)) (err error) {
func (s *service) ModifyDetailsAndUpdateLastUsed(objectId string, modifier func(current *domain.Details) (*domain.Details, error)) (err error) {
return cache.Do(s.objectGetter, objectId, func(du basic.DetailsUpdatable) error {
return du.UpdateDetailsAndLastUsed(modifier)
})
@ -135,15 +133,15 @@ func (s *service) ModifyDetailsList(req *pb.RpcObjectListModifyDetailValuesReque
if i == 0 {
modifyDetailsFunc = s.ModifyDetailsAndUpdateLastUsed
}
err := modifyDetailsFunc(objectId, func(current *types.Struct) (*types.Struct, error) {
err := modifyDetailsFunc(objectId, func(current *domain.Details) (*domain.Details, error) {
for _, op := range req.Operations {
if !pbtypes.IsNullValue(op.Set) {
// Set operation has higher priority than Add and Remove, because it modifies full value
current.Fields[op.RelationKey] = op.Set
current.Set(domain.RelationKey(op.RelationKey), domain.ValueFromProto(op.Set))
continue
}
addValueToListDetail(current, op.RelationKey, op.Add)
removeValueFromListDetail(current, op.RelationKey, op.Remove)
addValueToListDetail(current, domain.RelationKey(op.RelationKey), domain.ValueFromProto(op.Add))
removeValueFromListDetail(current, domain.RelationKey(op.RelationKey), domain.ValueFromProto(op.Remove))
}
return current, nil
})
@ -163,44 +161,51 @@ func (s *service) ModifyDetailsList(req *pb.RpcObjectListModifyDetailValuesReque
}
// addValueToListDetail adds values to int lists and string lists
func addValueToListDetail(s *types.Struct, key string, v *types.Value) {
if pbtypes.IsStructEmpty(s) || v == nil {
func addValueToListDetail(s *domain.Details, key domain.RelationKey, v domain.Value) {
if s.Len() == 0 || v.IsNull() {
return
}
toAdd := pbtypes.GetList(v)
oldValues := pbtypes.GetValueList(s, key)
newValues := slice.MergeUniqBy(oldValues, toAdd, func(this *types.Value, that *types.Value) bool {
toAdd := v.WrapToList()
oldValues := s.Get(key).WrapToList()
newValues := slice.MergeUniqBy(oldValues, toAdd, func(this domain.Value, that domain.Value) bool {
return this.Equal(that)
})
s.Fields[key] = &types.Value{
Kind: &types.Value_ListValue{ListValue: &types.ListValue{Values: newValues}},
}
s.Set(key, domain.ValueList(newValues))
}
// removeValueFromListDetail removes values from int lists and string lists
func removeValueFromListDetail(s *types.Struct, key string, v *types.Value) {
if pbtypes.IsStructEmpty(s) || v == nil {
func removeValueFromListDetail(s *domain.Details, key domain.RelationKey, v domain.Value) {
if s.Len() == 0 || v.IsNull() {
return
}
value := pbtypes.Get(s, key)
if value == nil {
value, ok := s.TryGet(key)
if !ok {
return
}
if value.Equal(v) {
delete(s.Fields, key)
s.Delete(key)
return
}
oldValues := pbtypes.GetList(value)
oldValues := value.WrapToList()
if len(oldValues) == 0 {
return
}
toDelete := pbtypes.GetList(v)
newValues := lo.Filter(oldValues, func(oldValue *types.Value, _ int) bool {
return !slices.ContainsFunc(toDelete, func(valueToDelete *types.Value) bool {
toDelete := v.WrapToList()
newValues := lo.Filter(oldValues, func(oldValue domain.Value, _ int) bool {
return !slices.ContainsFunc(toDelete, func(valueToDelete domain.Value) bool {
return oldValue.Equal(valueToDelete)
})
})
s.Fields[key] = &types.Value{
Kind: &types.Value_ListValue{ListValue: &types.ListValue{Values: newValues}},
if len(newValues) == 0 {
if value.IsStringList() {
s.Set(key, domain.StringList(nil))
} else {
s.Set(key, domain.Float64List(nil))
}
} else {
s.Set(key, domain.ValueList(newValues))
}
}

View file

@ -5,7 +5,6 @@ import (
"fmt"
"testing"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
@ -19,6 +18,7 @@ import (
"github.com/anyproto/anytype-heart/core/block/restriction"
"github.com/anyproto/anytype-heart/core/block/restriction/mock_restriction"
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
coresb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
@ -73,10 +73,10 @@ func newFixture(t *testing.T) *fixture {
}
func TestService_SetDetailsList(t *testing.T) {
details := []*model.Detail{
{Key: bundle.RelationKeyAssignee.String(), Value: pbtypes.String("Mark Twain")},
{Key: bundle.RelationKeyDone.String(), Value: pbtypes.Bool(true)},
{Key: bundle.RelationKeyLinkedProjects.String(), Value: pbtypes.StringList([]string{"important", "urgent"})},
details := []domain.Detail{
{Key: bundle.RelationKeyAssignee, Value: domain.String("Mark Twain")},
{Key: bundle.RelationKeyDone, Value: domain.Bool(true)},
{Key: bundle.RelationKeyLinkedProjects, Value: domain.StringList([]string{"important", "urgent"})},
}
t.Run("lastUsed is updated once", func(t *testing.T) {
@ -109,9 +109,9 @@ func TestService_SetDetailsList(t *testing.T) {
assert.Len(t, objects["obj2"].Results.LastUsedUpdates, 0)
assert.Len(t, objects["obj3"].Results.LastUsedUpdates, 0)
assert.Equal(t, "Mark Twain", pbtypes.GetString(objects["obj1"].NewState().Details(), bundle.RelationKeyAssignee.String()))
assert.True(t, pbtypes.GetBool(objects["obj2"].NewState().Details(), bundle.RelationKeyDone.String()))
assert.Equal(t, []string{"important", "urgent"}, pbtypes.GetStringList(objects["obj3"].NewState().Details(), bundle.RelationKeyLinkedProjects.String()))
assert.Equal(t, "Mark Twain", objects["obj1"].NewState().Details().GetString(bundle.RelationKeyAssignee))
assert.True(t, objects["obj2"].NewState().Details().GetBool(bundle.RelationKeyDone))
assert.Equal(t, []string{"important", "urgent"}, objects["obj3"].NewState().Details().GetStringList(bundle.RelationKeyLinkedProjects))
})
t.Run("some updates failed", func(t *testing.T) {
@ -148,9 +148,9 @@ func TestService_SetDetailsList(t *testing.T) {
func TestService_ModifyDetailsList(t *testing.T) {
ops := []*pb.RpcObjectListModifyDetailValuesRequestOperation{
{RelationKey: bundle.RelationKeyName.String(), Set: pbtypes.String("My favorite page")},
{RelationKey: bundle.RelationKeyLinks.String(), Add: pbtypes.String("some link")},
{RelationKey: bundle.RelationKeyDone.String(), Set: pbtypes.Bool(true)},
{RelationKey: bundle.RelationKeyName.String(), Set: domain.String("My favorite page").ToProto()},
{RelationKey: bundle.RelationKeyLinks.String(), Add: domain.String("some link").ToProto()},
{RelationKey: bundle.RelationKeyDone.String(), Set: domain.Bool(true).ToProto()},
}
t.Run("lastUsed is updated once", func(t *testing.T) {
@ -222,7 +222,7 @@ func TestService_ModifyDetailsList(t *testing.T) {
// given
fx := newFixture(t)
object := smarttest.New("obj1")
err := object.SetDetails(nil, []*model.Detail{{Key: bundle.RelationKeyDone.String(), Value: pbtypes.Bool(true)}}, false)
err := object.SetDetails(nil, []domain.Detail{{Key: bundle.RelationKeyDone, Value: domain.Bool(true)}}, false)
require.NoError(t, err)
fx.getter.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
return object, nil
@ -240,18 +240,18 @@ func TestService_ModifyDetailsList(t *testing.T) {
// then
assert.NoError(t, err)
assert.False(t, pbtypes.GetBool(object.Details(), bundle.RelationKeyDone.String()))
assert.False(t, object.Details().GetBool(bundle.RelationKeyDone))
})
}
func TestService_SetSpaceInfo(t *testing.T) {
var (
wsObjectId = "workspace"
details = &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyName.String(): pbtypes.String("My space"),
bundle.RelationKeyIconOption.String(): pbtypes.Int64(5),
bundle.RelationKeyIconImage.String(): pbtypes.String("kitten.jpg"),
}}
details = domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyName: domain.String("My space"),
bundle.RelationKeyIconOption: domain.Int64(5),
bundle.RelationKeyIconImage: domain.String("kitten.jpg"),
})
)
t.Run("no error", func(t *testing.T) {
@ -269,9 +269,9 @@ func TestService_SetSpaceInfo(t *testing.T) {
// then
assert.NoError(t, err)
assert.Equal(t, "My space", pbtypes.GetString(ws.NewState().Details(), bundle.RelationKeyName.String()))
assert.Equal(t, int64(5), pbtypes.GetInt64(ws.NewState().Details(), bundle.RelationKeyIconOption.String()))
assert.Equal(t, "kitten.jpg", pbtypes.GetString(ws.NewState().Details(), bundle.RelationKeyIconImage.String()))
assert.Equal(t, "My space", ws.NewState().Details().GetString(bundle.RelationKeyName))
assert.Equal(t, int64(5), ws.NewState().Details().GetInt64(bundle.RelationKeyIconOption))
assert.Equal(t, "kitten.jpg", ws.NewState().Details().GetString(bundle.RelationKeyIconImage))
})
t.Run("error on details setting", func(t *testing.T) {
@ -317,7 +317,7 @@ func TestService_SetWorkspaceDashboardId(t *testing.T) {
// then
assert.NoError(t, err)
assert.Equal(t, dashboardId, setId)
assert.Equal(t, dashboardId, pbtypes.GetString(sb.NewState().Details(), bundle.RelationKeySpaceDashboardId.String()))
assert.Equal(t, []string{dashboardId}, sb.NewState().Details().GetStringList(bundle.RelationKeySpaceDashboardId))
})
t.Run("error if wrong smartblock type", func(t *testing.T) {
@ -346,9 +346,9 @@ func TestService_SetWorkspaceDashboardId(t *testing.T) {
func TestService_SetListIsFavorite(t *testing.T) {
var (
objects = []objectstore.TestObject{
{bundle.RelationKeyId: pbtypes.String("obj1"), bundle.RelationKeySpaceId: pbtypes.String(spaceId)},
{bundle.RelationKeyId: pbtypes.String("obj2"), bundle.RelationKeySpaceId: pbtypes.String(spaceId)},
{bundle.RelationKeyId: pbtypes.String("obj3"), bundle.RelationKeySpaceId: pbtypes.String(spaceId)},
{bundle.RelationKeyId: domain.String("obj1"), bundle.RelationKeySpaceId: domain.String(spaceId)},
{bundle.RelationKeyId: domain.String("obj2"), bundle.RelationKeySpaceId: domain.String(spaceId)},
{bundle.RelationKeyId: domain.String("obj3"), bundle.RelationKeySpaceId: domain.String(spaceId)},
}
homeId = "home"
widgetId = "widget"
@ -467,7 +467,7 @@ func TestService_SetListIsFavorite(t *testing.T) {
func TestService_SetIsArchived(t *testing.T) {
var (
objects = []objectstore.TestObject{
{bundle.RelationKeyId: pbtypes.String("obj1"), bundle.RelationKeySpaceId: pbtypes.String(spaceId)},
{bundle.RelationKeyId: domain.String("obj1"), bundle.RelationKeySpaceId: domain.String(spaceId)},
}
binId = "bin"
)
@ -522,9 +522,9 @@ func TestService_SetIsArchived(t *testing.T) {
func TestService_SetListIsArchived(t *testing.T) {
var (
objects = []objectstore.TestObject{
{bundle.RelationKeyId: pbtypes.String("obj1"), bundle.RelationKeySpaceId: pbtypes.String(spaceId)},
{bundle.RelationKeyId: pbtypes.String("obj2"), bundle.RelationKeySpaceId: pbtypes.String(spaceId)},
{bundle.RelationKeyId: pbtypes.String("obj3"), bundle.RelationKeySpaceId: pbtypes.String(spaceId)},
{bundle.RelationKeyId: domain.String("obj1"), bundle.RelationKeySpaceId: domain.String(spaceId)},
{bundle.RelationKeyId: domain.String("obj2"), bundle.RelationKeySpaceId: domain.String(spaceId)},
{bundle.RelationKeyId: domain.String("obj3"), bundle.RelationKeySpaceId: domain.String(spaceId)},
}
binId = "bin"
)

View file

@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"github.com/gogo/protobuf/types"
"go.uber.org/zap"
"github.com/anyproto/anytype-heart/core/block/cache"
@ -15,18 +14,18 @@ import (
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/editor/widget"
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/session"
"github.com/anyproto/anytype-heart/pb"
"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/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)
var ErrUnexpectedBlockType = errors.New("unexpected block type")
func (s *service) SetSpaceInfo(spaceId string, details *types.Struct) error {
func (s *service) SetSpaceInfo(spaceId string, details *domain.Details) error {
ctx := context.TODO()
spc, err := s.spaceService.Get(ctx, spaceId)
if err != nil {
@ -34,9 +33,9 @@ func (s *service) SetSpaceInfo(spaceId string, details *types.Struct) error {
}
workspaceId := spc.DerivedIDs().Workspace
setDetails := make([]*model.Detail, 0, len(details.GetFields()))
for k, v := range details.GetFields() {
setDetails = append(setDetails, &model.Detail{
setDetails := make([]domain.Detail, 0, details.Len())
for k, v := range details.Iterate() {
setDetails = append(setDetails, domain.Detail{
Key: k,
Value: v,
})
@ -49,10 +48,10 @@ func (s *service) SetWorkspaceDashboardId(ctx session.Context, workspaceId strin
if ws.Type() != coresb.SmartBlockTypeWorkspace {
return ErrUnexpectedBlockType
}
if err = ws.SetDetails(ctx, []*model.Detail{
if err = ws.SetDetails(ctx, []domain.Detail{
{
Key: bundle.RelationKeySpaceDashboardId.String(),
Value: pbtypes.String(id),
Key: bundle.RelationKeySpaceDashboardId,
Value: domain.StringList([]string{id}),
},
}, false); err != nil {
return err

View file

@ -4,8 +4,6 @@ import (
"context"
"fmt"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/cache"
"github.com/anyproto/anytype-heart/core/block/editor/basic"
"github.com/anyproto/anytype-heart/core/block/editor/bookmark"
@ -26,6 +24,7 @@ import (
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/slice"
)
var ErrOptionUsedByOtherObjects = fmt.Errorf("option is used by other objects")
@ -365,7 +364,7 @@ func (s *Service) CreateAndUploadFile(
return
}
func (s *Service) UploadFile(ctx context.Context, spaceId string, req FileUploadRequest) (objectId string, details *types.Struct, err error) {
func (s *Service) UploadFile(ctx context.Context, spaceId string, req FileUploadRequest) (objectId string, details *domain.Details, err error) {
upl := s.fileUploaderService.NewUploader(spaceId, req.ObjectOrigin)
if req.DisableEncryption {
log.Errorf("DisableEncryption is deprecated and has no effect")
@ -375,7 +374,7 @@ func (s *Service) UploadFile(ctx context.Context, spaceId string, req FileUpload
upl.SetCustomEncryptionKeys(req.CustomEncryptionKeys)
}
upl.SetStyle(req.Style)
upl.SetAdditionalDetails(req.Details)
upl.SetAdditionalDetails(domain.NewDetailsFromProto(req.Details))
if req.Type != model.BlockContentFile_None {
upl.SetType(req.Type)
}
@ -475,7 +474,7 @@ func (s *Service) AddExtraRelations(ctx session.Context, objectId string, relati
return nil
}
return cache.Do(s, objectId, func(b smartblock.SmartBlock) error { // TODO RQ: check if empty
return b.AddRelationLinks(ctx, relationIds...)
return b.AddRelationLinks(ctx, slice.StringsInto[domain.RelationKey](relationIds)...)
})
}
@ -495,7 +494,7 @@ func (s *Service) SetObjectTypes(ctx session.Context, objectId string, objectTyp
func (s *Service) RemoveExtraRelations(ctx session.Context, objectTypeId string, relationKeys []string) (err error) {
return cache.Do(s, objectTypeId, func(b smartblock.SmartBlock) error {
return b.RemoveExtraRelations(ctx, relationKeys)
return b.RemoveExtraRelations(ctx, slice.StringsInto[domain.RelationKey](relationKeys))
})
}

View file

@ -12,7 +12,6 @@ import (
"github.com/anyproto/any-sync/app/logger"
"github.com/anyproto/any-sync/commonspace/object/accountdata"
"github.com/anyproto/any-sync/util/crypto"
"github.com/gogo/protobuf/types"
"go.uber.org/zap"
"github.com/anyproto/anytype-heart/core/anytype/config"
@ -34,7 +33,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/metricsid"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
var log = logger.NewNamedSugared("common.editor.accountobject")
@ -59,7 +57,7 @@ type AccountObject interface {
basic.DetailsSettable
SetSharedSpacesLimit(limit int) (err error)
SetProfileDetails(details *types.Struct) (err error)
SetProfileDetails(details *domain.Details) (err error)
MigrateIconImage(image string) (err error)
IsIconMigrated() (bool, error)
SetAnalyticsId(analyticsId string) (err error)
@ -86,11 +84,11 @@ type accountObject struct {
crdtDb anystore.DB
}
func (a *accountObject) SetDetails(ctx session.Context, details []*model.Detail, showEvent bool) (err error) {
func (a *accountObject) SetDetails(ctx session.Context, details []domain.Detail, showEvent bool) (err error) {
return a.bs.SetDetails(ctx, details, showEvent)
}
func (a *accountObject) SetDetailsAndUpdateLastUsed(ctx session.Context, details []*model.Detail, showEvent bool) (err error) {
func (a *accountObject) SetDetailsAndUpdateLastUsed(ctx session.Context, details []domain.Detail, showEvent bool) (err error) {
return a.bs.SetDetailsAndUpdateLastUsed(ctx, details, showEvent)
}
@ -208,8 +206,8 @@ func (a *accountObject) initState(st *state.State) error {
template.InitTemplate(st,
template.WithTitle,
template.WithForcedObjectTypes([]domain.TypeKey{bundle.TypeKeyProfile}),
template.WithForcedDetail(bundle.RelationKeyLayout, pbtypes.Float64(float64(model.ObjectType_profile))),
template.WithDetail(bundle.RelationKeyLayoutAlign, pbtypes.Float64(float64(model.Block_AlignCenter))),
template.WithForcedDetail(bundle.RelationKeyLayout, domain.Int64(model.ObjectType_profile)),
template.WithDetail(bundle.RelationKeyLayoutAlign, domain.Int64(model.Block_AlignCenter)),
)
blockId := "identity"
st.Set(simple.New(&model.Block{
@ -230,7 +228,7 @@ func (a *accountObject) initState(st *state.State) error {
if err != nil {
return fmt.Errorf("insert block: %w", err)
}
st.SetDetail(bundle.RelationKeyIsHidden.String(), pbtypes.Bool(true))
st.SetDetail(bundle.RelationKeyIsHidden, domain.Bool(true))
return nil
}
@ -337,19 +335,19 @@ func (a *accountObject) Close() error {
func (a *accountObject) SetSharedSpacesLimit(limit int) (err error) {
st := a.NewState()
st.SetDetailAndBundledRelation(bundle.RelationKeySharedSpacesLimit, pbtypes.Int64(int64(limit)))
st.SetDetailAndBundledRelation(bundle.RelationKeySharedSpacesLimit, domain.Int64(limit))
return a.Apply(st)
}
func (a *accountObject) GetSharedSpacesLimit() (limit int) {
return int(pbtypes.GetInt64(a.CombinedDetails(), bundle.RelationKeySharedSpacesLimit.String()))
return int(a.CombinedDetails().GetInt64(bundle.RelationKeySharedSpacesLimit))
}
func (a *accountObject) SetProfileDetails(details *types.Struct) (err error) {
func (a *accountObject) SetProfileDetails(details *domain.Details) (err error) {
st := a.NewState()
// we should set everything in local state, but not everything in the store (this should be filtered in OnPushChange)
for key, val := range details.Fields {
st.SetDetailAndBundledRelation(domain.RelationKey(key), val)
for key, value := range details.Iterate() {
st.SetDetailAndBundledRelation(key, value)
}
return a.Apply(st)
}
@ -357,7 +355,7 @@ func (a *accountObject) SetProfileDetails(details *types.Struct) (err error) {
func (a *accountObject) MigrateIconImage(image string) (err error) {
if image != "" {
st := a.NewState()
st.SetDetailAndBundledRelation(bundle.RelationKeyIconImage, pbtypes.String(image))
st.SetDetailAndBundledRelation(bundle.RelationKeyIconImage, domain.String(image))
err = a.Apply(st)
if err != nil {
return fmt.Errorf("set icon image: %w", err)

View file

@ -11,7 +11,6 @@ import (
"github.com/anyproto/any-store/anyenc"
"github.com/anyproto/any-sync/commonspace/object/accountdata"
"github.com/globalsign/mgo/bson"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
@ -23,6 +22,7 @@ import (
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/block/source"
"github.com/anyproto/anytype-heart/core/block/source/mock_source"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/util/metricsid"
@ -133,7 +133,7 @@ func (fx *fixture) assertStoreValue(t *testing.T, test any, extract func(val *an
require.Equal(t, test, extract(val))
}
func (fx *fixture) assertStateValue(t *testing.T, val any, extract func(str *types.Struct) any) {
func (fx *fixture) assertStateValue(t *testing.T, val any, extract func(str *domain.Details) any) {
require.Equal(t, val, extract(fx.SmartBlock.NewState().CombinedDetails()))
}
@ -175,11 +175,11 @@ func TestAccountOldInitWithData(t *testing.T) {
id, err := fx.GetAnalyticsId()
require.NoError(t, err)
require.Equal(t, "analyticsId", id)
fx.assertStateValue(t, "Anna", func(str *types.Struct) any {
return pbtypes.GetString(str, "name")
fx.assertStateValue(t, "Anna", func(str *domain.Details) any {
return str.GetString("name")
})
fx.assertStateValue(t, "Molly", func(str *types.Struct) any {
return pbtypes.GetString(str, "description")
fx.assertStateValue(t, "Molly", func(str *domain.Details) any {
return str.GetString("description")
})
require.NotNil(t, fx)
}
@ -189,11 +189,11 @@ func TestPushNewChanges(t *testing.T) {
fx := newFixture(t, true, nil)
_, err := fx.OnPushChange(makeStoreContent(map[string]any{"name": "Anna", "description": "Molly"}))
require.NoError(t, err)
fx.assertStateValue(t, "Anna", func(str *types.Struct) any {
return pbtypes.GetString(str, "name")
fx.assertStateValue(t, "Anna", func(str *domain.Details) any {
return str.GetString("name")
})
fx.assertStateValue(t, "Molly", func(str *types.Struct) any {
return pbtypes.GetString(str, "description")
fx.assertStateValue(t, "Molly", func(str *domain.Details) any {
return str.GetString("description")
})
require.NotNil(t, fx)
}

View file

@ -6,7 +6,7 @@ import (
"github.com/anyproto/any-store/anyenc"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/core/domain"
)
type KeyType int
@ -26,26 +26,26 @@ func newRelationsMapper(keys map[string]KeyType) *relationsMapper {
}
}
func (r *relationsMapper) GetRelationKey(key string, val *anyenc.Value) (*types.Value, bool) {
func (r *relationsMapper) GetRelationKey(key string, val *anyenc.Value) (domain.Value, bool) {
kt, ok := r.keys[key]
if !ok {
return nil, false
return domain.Invalid(), false
}
switch kt {
case KeyTypeString:
val := val.GetStringBytes(key)
if val == nil {
return nil, false
return domain.Invalid(), false
}
return pbtypes.String(string(val)), true
return domain.String(string(val)), true
case KeyTypeInt64:
val := val.GetInt(key)
if val == 0 {
return nil, false
return domain.Invalid(), false
}
return pbtypes.Int64(int64(val)), true
return domain.Int64(int64(val)), true
}
return nil, false
return domain.Invalid(), false
}
func (r *relationsMapper) GetStoreKey(key string, val *types.Value) (res any, ok bool) {

View file

@ -5,7 +5,6 @@ import (
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/editor/collection"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
@ -18,7 +17,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/database"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)
@ -63,7 +61,7 @@ func (p *Archive) CreationStateMigration(ctx *smartblock.InitContext) migration.
template.WithNoObjectTypes(),
template.WithDetailName("Archive"),
template.WithDetailIconEmoji("🗑"),
template.WithForcedDetail(bundle.RelationKeyIsHidden, pbtypes.Bool(true)),
template.WithForcedDetail(bundle.RelationKeyIsHidden, domain.Bool(true)),
)
},
}
@ -72,7 +70,7 @@ func (p *Archive) CreationStateMigration(ctx *smartblock.InitContext) migration.
func (p *Archive) StateMigrations() migration.Migrations {
return migration.MakeMigrations([]migration.Migration{{
Version: 2,
Proc: template.WithForcedDetail(bundle.RelationKeyIsHidden, pbtypes.Bool(true)),
Proc: template.WithForcedDetail(bundle.RelationKeyIsHidden, domain.Bool(true)),
}})
}
@ -97,9 +95,9 @@ func (p *Archive) updateObjects(_ smartblock.ApplyInfo) (err error) {
func (p *Archive) updateInStore(archivedIds []string) error {
records, err := p.objectStore.QueryRaw(&database.Filters{FilterObj: database.FiltersAnd{
database.FilterEq{
Key: bundle.RelationKeyIsArchived.String(),
Key: bundle.RelationKeyIsArchived,
Cond: model.BlockContentDataviewFilter_Equal,
Value: pbtypes.Bool(true),
Value: domain.Bool(true),
},
}}, 0, 0)
if err != nil {
@ -108,19 +106,17 @@ func (p *Archive) updateInStore(archivedIds []string) error {
var storeArchivedIds = make([]string, 0, len(records))
for _, rec := range records {
storeArchivedIds = append(storeArchivedIds, pbtypes.GetString(rec.Details, bundle.RelationKeyId.String()))
storeArchivedIds = append(storeArchivedIds, rec.Details.GetString(bundle.RelationKeyId))
}
removedIds, addedIds := slice.DifferenceRemovedAdded(storeArchivedIds, archivedIds)
for _, removedId := range removedIds {
go func(id string) {
if err := p.ModifyLocalDetails(id, func(current *types.Struct) (*types.Struct, error) {
if current == nil || current.Fields == nil {
current = &types.Struct{
Fields: map[string]*types.Value{},
}
if err := p.ModifyLocalDetails(id, func(current *domain.Details) (*domain.Details, error) {
if current == nil {
current = domain.NewDetails()
}
current.Fields[bundle.RelationKeyIsArchived.String()] = pbtypes.Bool(false)
current.SetBool(bundle.RelationKeyIsArchived, false)
return current, nil
}); err != nil {
logArchiveError(err)
@ -129,13 +125,11 @@ func (p *Archive) updateInStore(archivedIds []string) error {
}
for _, addedId := range addedIds {
go func(id string) {
if err := p.ModifyLocalDetails(id, func(current *types.Struct) (*types.Struct, error) {
if current == nil || current.Fields == nil {
current = &types.Struct{
Fields: map[string]*types.Value{},
}
if err := p.ModifyLocalDetails(id, func(current *domain.Details) (*domain.Details, error) {
if current == nil {
current = domain.NewDetails()
}
current.Fields[bundle.RelationKeyIsArchived.String()] = pbtypes.Bool(true)
current.SetBool(bundle.RelationKeyIsArchived, true)
return current, nil
}); err != nil {
logArchiveError(err)

View file

@ -3,7 +3,6 @@ package basic
import (
"fmt"
"github.com/gogo/protobuf/types"
"github.com/samber/lo"
"github.com/anyproto/anytype-heart/core/block/editor/converter"
@ -27,7 +26,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)
@ -65,13 +63,13 @@ type CommonOperations interface {
}
type DetailsSettable interface {
SetDetails(ctx session.Context, details []*model.Detail, showEvent bool) (err error)
SetDetailsAndUpdateLastUsed(ctx session.Context, details []*model.Detail, showEvent bool) (err error)
SetDetails(ctx session.Context, details []domain.Detail, showEvent bool) (err error)
SetDetailsAndUpdateLastUsed(ctx session.Context, details []domain.Detail, showEvent bool) (err error)
}
type DetailsUpdatable interface {
UpdateDetails(update func(current *types.Struct) (*types.Struct, error)) (err error)
UpdateDetailsAndLastUsed(update func(current *types.Struct) (*types.Struct, error)) (err error)
UpdateDetails(update func(current *domain.Details) (*domain.Details, error)) (err error)
UpdateDetailsAndLastUsed(update func(current *domain.Details) (*domain.Details, error)) (err error)
}
type Restrictionable interface {
@ -435,7 +433,7 @@ func (bs *basic) AddRelationAndSet(ctx session.Context, req pb.RpcBlockRelationA
func (bs *basic) FeaturedRelationAdd(ctx session.Context, relations ...string) (err error) {
s := bs.NewStateCtx(ctx)
fr := pbtypes.GetStringList(s.Details(), bundle.RelationKeyFeaturedRelations.String())
fr := s.Details().GetStringList(bundle.RelationKeyFeaturedRelations)
frc := make([]string, len(fr))
copy(frc, fr)
for _, r := range relations {
@ -447,7 +445,7 @@ func (bs *basic) FeaturedRelationAdd(ctx session.Context, relations ...string) (
}
frc = append(frc, r)
if !bs.HasRelation(s, r) {
err = bs.addRelationLink(s, r)
err = bs.addRelationLink(s, domain.RelationKey(r))
if err != nil {
return fmt.Errorf("failed to add relation link on adding featured relation '%s': %w", r, err)
}
@ -455,14 +453,14 @@ func (bs *basic) FeaturedRelationAdd(ctx session.Context, relations ...string) (
}
}
if len(frc) != len(fr) {
s.SetDetail(bundle.RelationKeyFeaturedRelations.String(), pbtypes.StringList(frc))
s.SetDetail(bundle.RelationKeyFeaturedRelations, domain.StringList(frc))
}
return bs.Apply(s, smartblock.NoRestrictions)
}
func (bs *basic) FeaturedRelationRemove(ctx session.Context, relations ...string) (err error) {
s := bs.NewStateCtx(ctx)
fr := pbtypes.GetStringList(s.Details(), bundle.RelationKeyFeaturedRelations.String())
fr := s.Details().GetStringList(bundle.RelationKeyFeaturedRelations)
frc := make([]string, len(fr))
copy(frc, fr)
for _, r := range relations {
@ -476,7 +474,7 @@ func (bs *basic) FeaturedRelationRemove(ctx session.Context, relations ...string
}
}
if len(frc) != len(fr) {
s.SetDetail(bundle.RelationKeyFeaturedRelations.String(), pbtypes.StringList(frc))
s.SetDetail(bundle.RelationKeyFeaturedRelations, domain.StringList(frc))
}
return bs.Apply(s, smartblock.NoRestrictions)
}
@ -504,8 +502,9 @@ func (bs *basic) ReplaceLink(oldId, newId string) error {
details := s.Details()
for _, rel := range rels {
if rel.Format == model.RelationFormat_object {
if pbtypes.GetString(details, rel.Key) == oldId {
s.SetDetail(rel.Key, pbtypes.String(newId))
key := domain.RelationKey(rel.Key)
if details.GetString(key) == oldId {
s.SetDetail(key, domain.String(newId))
}
}
}

View file

@ -164,12 +164,12 @@ func TestBasic_Duplicate(t *testing.T) {
AddBlock(simple.New(&model.Block{Id: "f1", Content: &model.BlockContentOfFile{File: &model.BlockContentFile{TargetObjectId: "file1_space1"}}})).
AddBlock(simple.New(&model.Block{Id: "f2", Content: &model.BlockContentOfFile{File: &model.BlockContentFile{TargetObjectId: "file2_space1"}}}))
ss := source.NewState()
ss.SetDetail(bundle.RelationKeySpaceId.String(), pbtypes.String(tc.spaceIds[0]))
ss.SetDetail(bundle.RelationKeySpaceId, domain.String(tc.spaceIds[0]))
target := smarttest.New("target").
AddBlock(simple.New(&model.Block{Id: "target"}))
ts := target.NewState()
ts.SetDetail(bundle.RelationKeySpaceId.String(), pbtypes.String(tc.spaceIds[1]))
ts.SetDetail(bundle.RelationKeySpaceId, domain.String(tc.spaceIds[1]))
// when
newIds, err := NewBasic(source, nil, nil, tc.fos(), nil).Duplicate(ss, ts, "target", model.Block_Inner, []string{"1", "f1"})
@ -666,14 +666,14 @@ func TestBasic_FeaturedRelationAdd(t *testing.T) {
require.NoError(t, b.FeaturedRelationAdd(nil, newRel...))
res := sb.NewState()
assert.Equal(t, newRel, pbtypes.GetStringList(res.Details(), bundle.RelationKeyFeaturedRelations.String()))
assert.Equal(t, newRel, res.Details().GetStringList(bundle.RelationKeyFeaturedRelations))
assert.NotNil(t, res.Pick(template.DescriptionBlockId))
}
func TestBasic_FeaturedRelationRemove(t *testing.T) {
sb := smarttest.New("test")
s := sb.NewState()
s.SetDetail(bundle.RelationKeyFeaturedRelations.String(), pbtypes.StringList([]string{bundle.RelationKeyDescription.String(), bundle.RelationKeyName.String()}))
s.SetDetail(bundle.RelationKeyFeaturedRelations, domain.StringList([]string{bundle.RelationKeyDescription.String(), bundle.RelationKeyName.String()}))
template.WithDescription(s)
require.NoError(t, sb.Apply(s))
@ -681,7 +681,7 @@ func TestBasic_FeaturedRelationRemove(t *testing.T) {
require.NoError(t, b.FeaturedRelationRemove(nil, bundle.RelationKeyDescription.String()))
res := sb.NewState()
assert.Equal(t, []string{bundle.RelationKeyName.String()}, pbtypes.GetStringList(res.Details(), bundle.RelationKeyFeaturedRelations.String()))
assert.Equal(t, []string{bundle.RelationKeyName.String()}, res.Details().GetStringList(bundle.RelationKeyFeaturedRelations))
assert.Nil(t, res.PickParentOf(template.DescriptionBlockId))
}
@ -690,7 +690,7 @@ func TestBasic_ReplaceLink(t *testing.T) {
sb := smarttest.New("test")
s := sb.NewState()
s.SetDetail("link", pbtypes.String(oldId))
s.SetDetail("link", domain.String(oldId))
s.AddRelationLinks(&model.RelationLink{Key: "link", Format: model.RelationFormat_object})
template.WithDescription(s)
newBlocks := []simple.Block{
@ -718,7 +718,7 @@ func TestBasic_ReplaceLink(t *testing.T) {
require.NoError(t, b.ReplaceLink(oldId, newId))
res := sb.NewState()
assert.Equal(t, newId, pbtypes.GetString(res.Details(), "link"))
assert.Equal(t, newId, res.Details().GetString("link"))
assert.Equal(t, newId, res.Pick(newBlocks[0].Model().Id).Model().GetLink().TargetBlockId)
assert.Equal(t, newId, res.Pick(newBlocks[1].Model().Id).Model().GetText().GetMarks().Marks[0].Param)
}

View file

@ -6,9 +6,6 @@ import (
"strings"
"time"
"github.com/gogo/protobuf/types"
"golang.org/x/exp/maps"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/restriction"
@ -21,23 +18,17 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/internalflag"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/uri"
)
var log = logging.Logger("anytype-mw-editor-basic")
type detailUpdate struct {
key string
value *types.Value
}
func (bs *basic) SetDetails(ctx session.Context, details []*model.Detail, showEvent bool) (err error) {
func (bs *basic) SetDetails(ctx session.Context, details []domain.Detail, showEvent bool) (err error) {
_, err = bs.setDetails(ctx, details, showEvent)
return err
}
func (bs *basic) SetDetailsAndUpdateLastUsed(ctx session.Context, details []*model.Detail, showEvent bool) (err error) {
func (bs *basic) SetDetailsAndUpdateLastUsed(ctx session.Context, details []domain.Detail, showEvent bool) (err error) {
var keys []domain.RelationKey
keys, err = bs.setDetails(ctx, details, showEvent)
if err != nil {
@ -50,7 +41,7 @@ func (bs *basic) SetDetailsAndUpdateLastUsed(ctx session.Context, details []*mod
return nil
}
func (bs *basic) setDetails(ctx session.Context, details []*model.Detail, showEvent bool) (updatedKeys []domain.RelationKey, err error) {
func (bs *basic) setDetails(ctx session.Context, details []domain.Detail, showEvent bool) (updatedKeys []domain.RelationKey, err error) {
s := bs.NewStateCtx(ctx)
// Collect updates handling special cases. These cases could update details themselves, so we
@ -71,37 +62,36 @@ func (bs *basic) setDetails(ctx session.Context, details []*model.Detail, showEv
return updatedKeys, nil
}
func (bs *basic) UpdateDetails(update func(current *types.Struct) (*types.Struct, error)) (err error) {
func (bs *basic) UpdateDetails(update func(current *domain.Details) (*domain.Details, error)) (err error) {
_, _, err = bs.updateDetails(update)
return err
}
func (bs *basic) UpdateDetailsAndLastUsed(update func(current *types.Struct) (*types.Struct, error)) (err error) {
var oldDetails, newDetails *types.Struct
oldDetails, newDetails, err = bs.updateDetails(update)
func (bs *basic) UpdateDetailsAndLastUsed(update func(current *domain.Details) (*domain.Details, error)) error {
oldDetails, newDetails, err := bs.updateDetails(update)
if err != nil {
return err
}
diff := pbtypes.StructDiff(oldDetails, newDetails)
if diff == nil || diff.Fields == nil {
diff := domain.StructDiff(oldDetails, newDetails)
if diff.Len() == 0 {
return nil
}
ts := time.Now().Unix()
for key := range diff.Fields {
bs.lastUsedUpdater.UpdateLastUsedDate(bs.SpaceID(), domain.RelationKey(key), ts)
for _, key := range diff.Keys() {
bs.lastUsedUpdater.UpdateLastUsedDate(bs.SpaceID(), key, ts)
}
return nil
}
func (bs *basic) updateDetails(update func(current *types.Struct) (*types.Struct, error)) (oldDetails, newDetails *types.Struct, err error) {
func (bs *basic) updateDetails(update func(current *domain.Details) (*domain.Details, error)) (oldDetails *domain.Details, newDetails *domain.Details, err error) {
if update == nil {
return nil, nil, fmt.Errorf("update function is nil")
}
s := bs.NewState()
oldDetails = s.CombinedDetails()
oldDetailsCopy := pbtypes.CopyStruct(oldDetails, true)
oldDetailsCopy := oldDetails.Copy()
newDetails, err = update(oldDetailsCopy)
if err != nil {
@ -109,21 +99,21 @@ func (bs *basic) updateDetails(update func(current *types.Struct) (*types.Struct
}
s.SetDetails(newDetails)
if err = bs.addRelationLinks(s, maps.Keys(newDetails.Fields)...); err != nil {
if err = bs.addRelationLinks(s, newDetails.Keys()...); err != nil {
return nil, nil, err
}
return oldDetails, newDetails, bs.Apply(s)
}
func (bs *basic) collectDetailUpdates(details []*model.Detail, s *state.State) ([]*detailUpdate, []domain.RelationKey) {
updates := make([]*detailUpdate, 0, len(details))
func (bs *basic) collectDetailUpdates(details []domain.Detail, s *state.State) ([]domain.Detail, []domain.RelationKey) {
updates := make([]domain.Detail, 0, len(details))
keys := make([]domain.RelationKey, 0, len(details))
for _, detail := range details {
update, err := bs.createDetailUpdate(s, detail)
if err == nil {
updates = append(updates, update)
keys = append(keys, domain.RelationKey(update.key))
keys = append(keys, update.Key)
} else {
log.Errorf("can't set detail %s: %s", detail.Key, err)
}
@ -131,129 +121,120 @@ func (bs *basic) collectDetailUpdates(details []*model.Detail, s *state.State) (
return updates, keys
}
func applyDetailUpdates(oldDetails *types.Struct, updates []*detailUpdate) *types.Struct {
newDetails := pbtypes.CopyStruct(oldDetails, false)
if newDetails == nil || newDetails.Fields == nil {
newDetails = &types.Struct{
Fields: make(map[string]*types.Value),
}
func applyDetailUpdates(oldDetails *domain.Details, updates []domain.Detail) *domain.Details {
newDetails := oldDetails.Copy()
if newDetails == nil {
newDetails = domain.NewDetails()
}
for _, update := range updates {
if update.value == nil {
delete(newDetails.Fields, update.key)
if update.Value.IsNull() {
newDetails.Delete(update.Key)
} else {
newDetails.Fields[update.key] = update.value
newDetails.Set(update.Key, update.Value)
}
}
return newDetails
}
func (bs *basic) createDetailUpdate(st *state.State, detail *model.Detail) (*detailUpdate, error) {
if detail.Value != nil {
if err := pbtypes.ValidateValue(detail.Value); err != nil {
return nil, fmt.Errorf("detail %s validation error: %w", detail.Key, err)
}
// TODO make no sense?
func (bs *basic) createDetailUpdate(st *state.State, detail domain.Detail) (domain.Detail, error) {
if detail.Value.Ok() {
if err := bs.setDetailSpecialCases(st, detail); err != nil {
return nil, fmt.Errorf("special case: %w", err)
return domain.Detail{}, fmt.Errorf("special case: %w", err)
}
if err := bs.addRelationLink(st, detail.Key); err != nil {
return nil, err
return domain.Detail{}, err
}
if err := bs.validateDetailFormat(bs.SpaceID(), detail.Key, detail.Value); err != nil {
return nil, fmt.Errorf("failed to validate relation: %w", err)
return domain.Detail{}, fmt.Errorf("failed to validate relation: %w", err)
}
}
return &detailUpdate{
key: detail.Key,
value: detail.Value,
return domain.Detail{
Key: detail.Key,
Value: detail.Value,
}, nil
}
func (bs *basic) validateDetailFormat(spaceID string, key string, v *types.Value) error {
r, err := bs.objectStore.FetchRelationByKey(key)
func (bs *basic) validateDetailFormat(spaceID string, key domain.RelationKey, v domain.Value) error {
if !v.Ok() {
return fmt.Errorf("invalid value")
}
r, err := bs.objectStore.FetchRelationByKey(key.String())
if err != nil {
return err
}
if _, isNull := v.Kind.(*types.Value_NullValue); isNull {
if v.IsNull() {
// allow null value for any field
return nil
}
switch r.Format {
case model.RelationFormat_longtext, model.RelationFormat_shorttext:
if _, ok := v.Kind.(*types.Value_StringValue); !ok {
return fmt.Errorf("incorrect type: %T instead of string", v.Kind)
if !v.IsString() {
return fmt.Errorf("incorrect type: %v instead of string", v)
}
return nil
case model.RelationFormat_number:
if _, ok := v.Kind.(*types.Value_NumberValue); !ok {
return fmt.Errorf("incorrect type: %T instead of number", v.Kind)
if !v.IsFloat64() {
return fmt.Errorf("incorrect type: %v instead of number", v)
}
return nil
case model.RelationFormat_status:
if _, ok := v.Kind.(*types.Value_StringValue); ok {
} else if _, ok := v.Kind.(*types.Value_ListValue); !ok {
return fmt.Errorf("incorrect type: %T instead of list", v.Kind)
vals, ok := v.TryStringList()
if !ok {
return fmt.Errorf("incorrect type: %v instead of string list", v)
}
vals := pbtypes.GetStringListValue(v)
if len(vals) > 1 {
return fmt.Errorf("status should not contain more than one value")
}
return bs.validateOptions(r, vals)
case model.RelationFormat_tag:
if _, ok := v.Kind.(*types.Value_ListValue); !ok {
return fmt.Errorf("incorrect type: %T instead of list", v.Kind)
vals, ok := v.TryStringList()
if !ok {
return fmt.Errorf("incorrect type: %v instead of string list", v)
}
vals := pbtypes.GetStringListValue(v)
if r.MaxCount > 0 && len(vals) > int(r.MaxCount) {
return fmt.Errorf("maxCount exceeded")
}
return bs.validateOptions(r, vals)
case model.RelationFormat_date:
if _, ok := v.Kind.(*types.Value_NumberValue); !ok {
return fmt.Errorf("incorrect type: %T instead of number", v.Kind)
if !v.IsFloat64() {
return fmt.Errorf("incorrect type: %v instead of number", v)
}
return nil
case model.RelationFormat_file, model.RelationFormat_object:
switch s := v.Kind.(type) {
case *types.Value_StringValue:
return nil
case *types.Value_ListValue:
if r.MaxCount > 0 && len(s.ListValue.Values) > int(r.MaxCount) {
return fmt.Errorf("relation %s(%s) has maxCount exceeded", r.Key, r.Format.String())
}
for i, lv := range s.ListValue.Values {
if optId, ok := lv.Kind.(*types.Value_StringValue); !ok {
return fmt.Errorf("incorrect list item value at index %d: %T instead of string", i, lv.Kind)
} else if optId.StringValue == "" {
return fmt.Errorf("empty option at index %d", i)
}
}
return nil
default:
return fmt.Errorf("incorrect type: %T instead of list/string", v.Kind)
vals, ok := v.TryStringList()
if !ok {
return fmt.Errorf("incorrect type: %v instead of string list", v)
}
if r.MaxCount > 0 && len(vals) > int(r.MaxCount) {
return fmt.Errorf("relation %s(%s) has maxCount exceeded", r.Key, r.Format.String())
}
for i, lv := range vals {
if lv == "" {
return fmt.Errorf("empty option at index %d", i)
}
}
return nil
case model.RelationFormat_checkbox:
if _, ok := v.Kind.(*types.Value_BoolValue); !ok {
return fmt.Errorf("incorrect type: %T instead of bool", v.Kind)
if !v.IsBool() {
return fmt.Errorf("incorrect type: %v instead of bool", v)
}
return nil
case model.RelationFormat_url:
if _, ok := v.Kind.(*types.Value_StringValue); !ok {
return fmt.Errorf("incorrect type: %T instead of string", v.Kind)
val, ok := v.TryString()
if !ok {
return fmt.Errorf("incorrect type: %v instead of string", v)
}
s := strings.TrimSpace(v.GetStringValue())
s := strings.TrimSpace(val)
if s != "" {
err := uri.ValidateURI(strings.TrimSpace(v.GetStringValue()))
err := uri.ValidateURI(s)
if err != nil {
return fmt.Errorf("failed to parse URL: %w", err)
}
@ -264,8 +245,9 @@ func (bs *basic) validateDetailFormat(spaceID string, key string, v *types.Value
// }
return nil
case model.RelationFormat_email:
if _, ok := v.Kind.(*types.Value_StringValue); !ok {
return fmt.Errorf("incorrect type: %T instead of string", v.Kind)
_, ok := v.TryString()
if !ok {
return fmt.Errorf("incorrect type: %v instead of string", v)
}
// todo: revise regexp and reimplement
/*valid := uri.ValidateEmail(v.GetStringValue())
@ -274,8 +256,9 @@ func (bs *basic) validateDetailFormat(spaceID string, key string, v *types.Value
}*/
return nil
case model.RelationFormat_phone:
if _, ok := v.Kind.(*types.Value_StringValue); !ok {
return fmt.Errorf("incorrect type: %T instead of string", v.Kind)
_, ok := v.TryString()
if !ok {
return fmt.Errorf("incorrect type: %v instead of string", v)
}
// todo: revise regexp and reimplement
@ -285,8 +268,9 @@ func (bs *basic) validateDetailFormat(spaceID string, key string, v *types.Value
}*/
return nil
case model.RelationFormat_emoji:
if _, ok := v.Kind.(*types.Value_StringValue); !ok {
return fmt.Errorf("incorrect type: %T instead of string", v.Kind)
_, ok := v.TryString()
if !ok {
return fmt.Errorf("incorrect type: %v instead of string", v)
}
// check if the symbol is emoji
@ -301,19 +285,19 @@ func (bs *basic) validateOptions(rel *relationutils.Relation, v []string) error
return nil
}
func (bs *basic) setDetailSpecialCases(st *state.State, detail *model.Detail) error {
if detail.Key == bundle.RelationKeyType.String() {
func (bs *basic) setDetailSpecialCases(st *state.State, detail domain.Detail) error {
if detail.Key == bundle.RelationKeyType {
return fmt.Errorf("can't change object type directly: %w", domain.ErrValidationFailed)
}
if detail.Key == bundle.RelationKeyLayout.String() {
if detail.Key == bundle.RelationKeyLayout {
// special case when client sets the layout detail directly instead of using SetLayoutInState command
return bs.SetLayoutInState(st, model.ObjectTypeLayout(detail.Value.GetNumberValue()), false)
return bs.SetLayoutInState(st, model.ObjectTypeLayout(detail.Value.Int64()), false)
}
return nil
}
func (bs *basic) addRelationLink(st *state.State, relationKey string) error {
relLink, err := bs.objectStore.GetRelationLink(relationKey)
func (bs *basic) addRelationLink(st *state.State, relationKey domain.RelationKey) error {
relLink, err := bs.objectStore.GetRelationLink(relationKey.String())
if err != nil || relLink == nil {
return fmt.Errorf("failed to get relation: %w", err)
}
@ -322,7 +306,7 @@ func (bs *basic) addRelationLink(st *state.State, relationKey string) error {
}
// addRelationLinks is deprecated and will be removed in release 7
func (bs *basic) addRelationLinks(st *state.State, relationKeys ...string) error {
func (bs *basic) addRelationLinks(st *state.State, relationKeys ...domain.RelationKey) error {
if len(relationKeys) == 0 {
return nil
}
@ -394,7 +378,7 @@ func (bs *basic) SetObjectTypesInState(s *state.State, objectTypeKeys []domain.T
s.SetObjectTypeKeys(objectTypeKeys)
removeInternalFlags(s)
if pbtypes.GetInt64(bs.CombinedDetails(), bundle.RelationKeyOrigin.String()) == int64(model.ObjectOrigin_none) {
if bs.CombinedDetails().GetInt64(bundle.RelationKeyOrigin) == int64(model.ObjectOrigin_none) {
bs.lastUsedUpdater.UpdateLastUsedDate(bs.SpaceID(), objectTypeKeys[0], time.Now().Unix())
}
@ -414,7 +398,7 @@ func (bs *basic) getLayoutForType(objectTypeKey domain.TypeKey) (model.ObjectTyp
if err != nil {
return 0, fmt.Errorf("get object by unique key: %w", err)
}
rawLayout := pbtypes.GetInt64(typeDetails.GetDetails(), bundle.RelationKeyRecommendedLayout.String())
rawLayout := typeDetails.GetInt64(bundle.RelationKeyRecommendedLayout)
return model.ObjectTypeLayout(rawLayout), nil
}
@ -426,7 +410,7 @@ func (bs *basic) SetLayoutInState(s *state.State, toLayout model.ObjectTypeLayou
}
fromLayout, _ := s.Layout()
s.SetDetail(bundle.RelationKeyLayout.String(), pbtypes.Int64(int64(toLayout)))
s.SetDetail(bundle.RelationKeyLayout, domain.Int64(toLayout))
if err = bs.layoutConverter.Convert(s, fromLayout, toLayout); err != nil {
return fmt.Errorf("convert layout: %w", err)
}

View file

@ -3,7 +3,6 @@ package basic
import (
"testing"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
@ -16,7 +15,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
type basicFixture struct {
@ -54,92 +52,94 @@ func TestBasic_UpdateDetails(t *testing.T) {
// given
f := newBasicFixture(t)
f.store.AddObjects(t, []objectstore.TestObject{{
bundle.RelationKeyId: pbtypes.String("rel-aperture"),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyRelationKey: pbtypes.String("aperture"),
bundle.RelationKeyUniqueKey: pbtypes.String("rel-aperture"),
bundle.RelationKeyRelationFormat: pbtypes.Int64(int64(model.RelationFormat_longtext)),
bundle.RelationKeyId: domain.String("rel-aperture"),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyRelationKey: domain.String("aperture"),
bundle.RelationKeyUniqueKey: domain.String("rel-aperture"),
bundle.RelationKeyRelationFormat: domain.Int64(int64(model.RelationFormat_longtext)),
}, {
bundle.RelationKeyId: pbtypes.String("rel-maxCount"),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyRelationKey: pbtypes.String("relationMaxCount"),
bundle.RelationKeyUniqueKey: pbtypes.String("rel-relationMaxCount"),
bundle.RelationKeyRelationFormat: pbtypes.Int64(int64(model.RelationFormat_number)),
bundle.RelationKeyId: domain.String("rel-maxCount"),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyRelationKey: domain.String("relationMaxCount"),
bundle.RelationKeyUniqueKey: domain.String("rel-relationMaxCount"),
bundle.RelationKeyRelationFormat: domain.Int64(int64(model.RelationFormat_number)),
}})
// when
err := f.basic.UpdateDetails(func(current *types.Struct) (*types.Struct, error) {
current.Fields[bundle.RelationKeyAperture.String()] = pbtypes.String("aperture")
current.Fields[bundle.RelationKeyRelationMaxCount.String()] = pbtypes.Int64(5)
err := f.basic.UpdateDetails(func(current *domain.Details) (*domain.Details, error) {
current.Set(bundle.RelationKeyAperture, domain.String("aperture"))
current.Set(bundle.RelationKeyRelationMaxCount, domain.Int64(5))
return current, nil
})
// then
assert.NoError(t, err)
value, found := f.sb.Details().Fields[bundle.RelationKeyAperture.String()]
value, found := f.sb.Details().TryString(bundle.RelationKeyAperture)
assert.True(t, found)
assert.Equal(t, pbtypes.String("aperture"), value)
assert.Equal(t, "aperture", value)
assert.True(t, f.sb.HasRelation(f.sb.NewState(), bundle.RelationKeyAperture.String()))
value, found = f.sb.Details().Fields[bundle.RelationKeyRelationMaxCount.String()]
assert.True(t, found)
assert.Equal(t, pbtypes.Int64(5), value)
assert.True(t, f.sb.HasRelation(f.sb.NewState(), bundle.RelationKeyRelationMaxCount.String()))
{
value, found := f.sb.Details().TryInt64(bundle.RelationKeyRelationMaxCount)
assert.True(t, found)
assert.Equal(t, int64(5), value)
assert.True(t, f.sb.HasRelation(f.sb.NewState(), bundle.RelationKeyRelationMaxCount.String()))
}
})
t.Run("modify details", func(t *testing.T) {
// given
f := newBasicFixture(t)
err := f.sb.SetDetails(nil, []*model.Detail{{
Key: bundle.RelationKeySpaceDashboardId.String(),
Value: pbtypes.String("123"),
err := f.sb.SetDetails(nil, []domain.Detail{{
Key: bundle.RelationKeySpaceDashboardId,
Value: domain.String("123"),
}}, false)
assert.NoError(t, err)
f.store.AddObjects(t, []objectstore.TestObject{{
bundle.RelationKeyId: pbtypes.String("rel-spaceDashboardId"),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyRelationKey: pbtypes.String("spaceDashboardId"),
bundle.RelationKeyUniqueKey: pbtypes.String("rel-spaceDashboardId"),
bundle.RelationKeyRelationFormat: pbtypes.Int64(int64(model.RelationFormat_object)),
bundle.RelationKeyId: domain.String("rel-spaceDashboardId"),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyRelationKey: domain.String("spaceDashboardId"),
bundle.RelationKeyUniqueKey: domain.String("rel-spaceDashboardId"),
bundle.RelationKeyRelationFormat: domain.Int64(int64(model.RelationFormat_object)),
}})
// when
err = f.basic.UpdateDetails(func(current *types.Struct) (*types.Struct, error) {
current.Fields[bundle.RelationKeySpaceDashboardId.String()] = pbtypes.String("new123")
err = f.basic.UpdateDetails(func(current *domain.Details) (*domain.Details, error) {
current.Set(bundle.RelationKeySpaceDashboardId, domain.String("new123"))
return current, nil
})
// then
assert.NoError(t, err)
value, found := f.sb.Details().Fields[bundle.RelationKeySpaceDashboardId.String()]
value, found := f.sb.Details().TryString(bundle.RelationKeySpaceDashboardId)
assert.True(t, found)
assert.Equal(t, pbtypes.String("new123"), value)
assert.Equal(t, "new123", value)
assert.True(t, f.sb.HasRelation(f.sb.NewState(), bundle.RelationKeySpaceDashboardId.String()))
})
t.Run("delete details", func(t *testing.T) {
// given
f := newBasicFixture(t)
err := f.sb.SetDetails(nil, []*model.Detail{{
Key: bundle.RelationKeyTargetObjectType.String(),
Value: pbtypes.String("ot-note"),
err := f.sb.SetDetails(nil, []domain.Detail{{
Key: bundle.RelationKeyTargetObjectType,
Value: domain.String("ot-note"),
}}, false)
assert.NoError(t, err)
// when
err = f.basic.UpdateDetails(func(current *types.Struct) (*types.Struct, error) {
delete(current.Fields, bundle.RelationKeyTargetObjectType.String())
err = f.basic.UpdateDetails(func(current *domain.Details) (*domain.Details, error) {
current.Delete(bundle.RelationKeyTargetObjectType)
return current, nil
})
// then
assert.NoError(t, err)
value, found := f.sb.Details().Fields[bundle.RelationKeyTargetObjectType.String()]
value, found := f.sb.Details().TryString(bundle.RelationKeyTargetObjectType)
assert.False(t, found)
assert.Nil(t, value)
assert.Empty(t, value)
assert.False(t, f.sb.HasRelation(f.sb.NewState(), bundle.RelationKeyTargetObjectType.String()))
})
}
@ -151,10 +151,10 @@ func TestBasic_SetObjectTypesInState(t *testing.T) {
f.lastUsed.EXPECT().UpdateLastUsedDate(mock.Anything, bundle.TypeKeyTask, mock.Anything).Return().Once()
f.store.AddObjects(t, []objectstore.TestObject{{
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyId: pbtypes.String("ot-task"),
bundle.RelationKeyUniqueKey: pbtypes.String("ot-task"),
bundle.RelationKeyLayout: pbtypes.Int64(int64(model.ObjectType_todo)),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyId: domain.String("ot-task"),
bundle.RelationKeyUniqueKey: domain.String("ot-task"),
bundle.RelationKeyLayout: domain.Int64(int64(model.ObjectType_todo)),
}})
s := f.sb.NewState()

View file

@ -5,7 +5,6 @@ import (
"fmt"
"github.com/globalsign/mgo/bson"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/state"
@ -19,12 +18,12 @@ import (
)
type ObjectCreator interface {
CreateSmartBlockFromState(ctx context.Context, spaceID string, objectTypeKeys []domain.TypeKey, createState *state.State) (id string, newDetails *types.Struct, err error)
CreateSmartBlockFromState(ctx context.Context, spaceID string, objectTypeKeys []domain.TypeKey, createState *state.State) (id string, newDetails *domain.Details, err error)
}
type TemplateStateCreator interface {
CreateTemplateStateWithDetails(templateId string, details *types.Struct) (*state.State, error)
CreateTemplateStateFromSmartBlock(sb smartblock.SmartBlock, details *types.Struct) *state.State
CreateTemplateStateWithDetails(templateId string, details *domain.Details) (*state.State, error)
CreateTemplateStateFromSmartBlock(sb smartblock.SmartBlock, details *domain.Details) *state.State
}
// ExtractBlocksToObjects extracts child blocks from the object to separate objects and
@ -94,12 +93,12 @@ func (bs *basic) prepareTargetObjectDetails(
spaceID string,
typeUniqueKey domain.UniqueKey,
rootBlock simple.Block,
) (*types.Struct, error) {
) (*domain.Details, error) {
objType, err := bs.objectStore.GetObjectByUniqueKey(typeUniqueKey)
if err != nil {
return nil, err
}
rawLayout := pbtypes.GetInt64(objType.GetDetails(), bundle.RelationKeyRecommendedLayout.String())
rawLayout := objType.GetInt64(bundle.RelationKeyRecommendedLayout)
details := createTargetObjectDetails(rootBlock.Model().GetText().GetText(), model.ObjectTypeLayout(rawLayout))
return details, nil
}
@ -177,17 +176,13 @@ func removeBlocks(state *state.State, descendants []simple.Block) {
}
}
func createTargetObjectDetails(nameText string, layout model.ObjectTypeLayout) *types.Struct {
fields := map[string]*types.Value{
bundle.RelationKeyLayout.String(): pbtypes.Int64(int64(layout)),
}
func createTargetObjectDetails(nameText string, layout model.ObjectTypeLayout) *domain.Details {
details := domain.NewDetails()
details.SetInt64(bundle.RelationKeyLayout, int64(layout))
// Without this check title will be duplicated in template.WithNameToFirstBlock
if layout != model.ObjectType_note {
fields[bundle.RelationKeyName.String()] = pbtypes.String(nameText)
details.SetString(bundle.RelationKeyName, nameText)
}
details := &types.Struct{Fields: fields}
return details
}
@ -257,5 +252,5 @@ func copySubtreeOfBlocks(s *state.State, oldRootId string, oldBlocks []simple.Bl
}
func hasNoteLayout(s *state.State) bool {
return model.ObjectTypeLayout(pbtypes.GetInt64(s.Details(), bundle.RelationKeyLayout.String())) == model.ObjectType_note
return model.ObjectTypeLayout(s.Details().GetInt64(bundle.RelationKeyLayout)) == model.ObjectType_note
}

View file

@ -5,7 +5,6 @@ import (
"testing"
"github.com/globalsign/mgo/bson"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -23,7 +22,6 @@ import (
coresb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)
@ -35,7 +33,7 @@ func (tc testCreator) Add(object *smarttest.SmartTest) {
tc.objects[object.Id()] = object
}
func (tc testCreator) CreateSmartBlockFromState(_ context.Context, _ string, _ []domain.TypeKey, createState *state.State) (id string, newDetails *types.Struct, err error) {
func (tc testCreator) CreateSmartBlockFromState(_ context.Context, _ string, _ []domain.TypeKey, createState *state.State) (id string, newdetails *domain.Details, err error) {
id = bson.NewObjectId().Hex()
object := smarttest.New(id)
tc.objects[id] = object
@ -54,7 +52,7 @@ func (tts testTemplateService) AddTemplate(id string, st *state.State) {
tts.templates[id] = st
}
func (tts testTemplateService) CreateTemplateStateWithDetails(id string, details *types.Struct) (st *state.State, err error) {
func (tts testTemplateService) CreateTemplateStateWithDetails(id string, details *domain.Details) (st *state.State, err error) {
if id == "" {
st = state.NewDoc("", nil).NewState()
template.InitTemplate(st, template.WithEmpty,
@ -67,12 +65,12 @@ func (tts testTemplateService) CreateTemplateStateWithDetails(id string, details
st = tts.templates[id]
}
templateDetails := st.Details()
newDetails := pbtypes.StructMerge(templateDetails, details, false)
newDetails := templateDetails.Merge(details)
st.SetDetails(newDetails)
return st, nil
}
func (tts testTemplateService) CreateTemplateStateFromSmartBlock(sb smartblock.SmartBlock, details *types.Struct) *state.State {
func (tts testTemplateService) CreateTemplateStateFromSmartBlock(sb smartblock.SmartBlock, details *domain.Details) *state.State {
return tts.templates[sb.Id()]
}
@ -106,14 +104,14 @@ func assertLinkedObjectHasTextBlocks(t *testing.T, ts testCreator, sourceObject
assertHasTextBlocks(t, object, texts)
}
func assertDetails(t *testing.T, id string, ts testCreator, details *types.Struct) {
func assertDetails(t *testing.T, id string, ts testCreator, details *domain.Details) {
object, ok := ts.objects[id]
if !ok {
return
}
objDetails := object.Details()
for key, value := range details.Fields {
assert.Equal(t, value, objDetails.Fields[key])
for key, value := range details.Iterate() {
assert.Equal(t, value, objDetails.Get(key))
}
}
@ -134,11 +132,11 @@ func TestExtractObjects(t *testing.T) {
return sb
}
templateDetails := []*model.Detail{
{Key: bundle.RelationKeyName.String(), Value: pbtypes.String("template")},
{Key: bundle.RelationKeyIconImage.String(), Value: pbtypes.String("very funny img")},
{Key: bundle.RelationKeyFeaturedRelations.String(), Value: pbtypes.StringList([]string{"tag", "type", "status"})},
{Key: bundle.RelationKeyCoverId.String(), Value: pbtypes.String("poster with Van Damme")},
templateDetails := []domain.Detail{
{Key: bundle.RelationKeyName, Value: domain.String("template")},
{Key: bundle.RelationKeyIconImage, Value: domain.String("very funny img")},
{Key: bundle.RelationKeyFeaturedRelations, Value: domain.StringList([]string{"tag", "type", "status"})},
{Key: bundle.RelationKeyCoverId, Value: domain.String("poster with Van Damme")},
}
makeTemplateState := func(id string) *state.State {
@ -158,7 +156,7 @@ func TestExtractObjects(t *testing.T) {
typeKey string
templateId string
wantObjectsWithTexts [][]string
wantDetails *types.Struct
wantDetails *domain.Details
}{
{
name: "undefined block",
@ -216,7 +214,7 @@ func TestExtractObjects(t *testing.T) {
"text 2.1",
},
},
wantDetails: &types.Struct{},
wantDetails: domain.NewDetails(),
},
{
name: "two blocks, not all descendants present in requests",
@ -248,12 +246,12 @@ func TestExtractObjects(t *testing.T) {
"text 3", "text 3.1", "text 3.1.1",
},
},
wantDetails: &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyName.String(): pbtypes.String("text 3"),
bundle.RelationKeyIconImage.String(): pbtypes.String("very funny img"),
bundle.RelationKeyFeaturedRelations.String(): pbtypes.StringList([]string{"tag", "type", "status"}),
bundle.RelationKeyCoverId.String(): pbtypes.String("poster with Van Damme"),
}},
wantDetails: domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyName: domain.String("text 3"),
bundle.RelationKeyIconImage: domain.String("very funny img"),
bundle.RelationKeyFeaturedRelations: domain.StringList([]string{"tag", "type", "status"}),
bundle.RelationKeyCoverId: domain.String("poster with Van Damme"),
}),
},
{
name: "two blocks with children, from template",
@ -271,20 +269,20 @@ func TestExtractObjects(t *testing.T) {
"text 3", "text 3.1", "text 3.1.1",
},
},
wantDetails: &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyIconImage.String(): pbtypes.String("very funny img"),
bundle.RelationKeyFeaturedRelations.String(): pbtypes.StringList([]string{"tag", "type", "status"}),
bundle.RelationKeyCoverId.String(): pbtypes.String("poster with Van Damme"),
}},
wantDetails: domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyIconImage: domain.String("very funny img"),
bundle.RelationKeyFeaturedRelations: domain.StringList([]string{"tag", "type", "status"}),
bundle.RelationKeyCoverId: domain.String("poster with Van Damme"),
}),
},
{
name: "if target layout includes title, root is not added",
blockIds: []string{"1.1"},
typeKey: bundle.TypeKeyTask.String(),
wantObjectsWithTexts: [][]string{{"text 1.1.1"}},
wantDetails: &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyName.String(): pbtypes.String("1.1"),
}},
wantDetails: domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyName: domain.String("1.1"),
}),
},
{
name: "template and source are the same objects",
@ -336,7 +334,7 @@ func TestExtractObjects(t *testing.T) {
require.Len(t, linkIds, len(tc.wantObjectsWithTexts))
for i, wantTexts := range tc.wantObjectsWithTexts {
assertLinkedObjectHasTextBlocks(t, creator, sb, linkIds[i], wantTexts)
if tc.wantDetails != nil && tc.wantDetails.Fields != nil {
if tc.wantDetails != nil {
assertDetails(t, linkIds[i], creator, tc.wantDetails)
}
}
@ -344,15 +342,15 @@ func TestExtractObjects(t *testing.T) {
}
t.Run("do not add relation name - when creating note", func(t *testing.T) {
fields := createTargetObjectDetails("whatever name", model.ObjectType_note).Fields
details := createTargetObjectDetails("whatever name", model.ObjectType_note)
assert.NotContains(t, fields, bundle.RelationKeyName.String())
assert.False(t, details.Has(bundle.RelationKeyName))
})
t.Run("add relation name - when creating not note", func(t *testing.T) {
fields := createTargetObjectDetails("whatever name", model.ObjectType_basic).Fields
details := createTargetObjectDetails("whatever name", model.ObjectType_basic)
assert.Contains(t, fields, bundle.RelationKeyName.String())
assert.True(t, details.Has(bundle.RelationKeyName))
})
t.Run("add custom link block", func(t *testing.T) {
fixture := newFixture(t)
@ -621,14 +619,14 @@ func newFixture(t *testing.T) *fixture {
objectStore.AddObjects(t, []spaceindex.TestObject{
{
bundle.RelationKeyId: pbtypes.String("id1"),
bundle.RelationKeyUniqueKey: pbtypes.String("ot-note"),
bundle.RelationKeyRecommendedLayout: pbtypes.Int64(int64(model.ObjectType_note)),
bundle.RelationKeyId: domain.String("id1"),
bundle.RelationKeyUniqueKey: domain.String("ot-note"),
bundle.RelationKeyRecommendedLayout: domain.Int64(int64(model.ObjectType_note)),
},
{
bundle.RelationKeyId: pbtypes.String("id2"),
bundle.RelationKeyUniqueKey: pbtypes.String("ot-task"),
bundle.RelationKeyRecommendedLayout: pbtypes.Int64(int64(model.ObjectType_todo)),
bundle.RelationKeyId: domain.String("id2"),
bundle.RelationKeyUniqueKey: domain.String("ot-task"),
bundle.RelationKeyRecommendedLayout: domain.Int64(int64(model.ObjectType_todo)),
},
})

View file

@ -6,7 +6,6 @@ import (
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/session"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
type IHistory interface {
@ -50,7 +49,7 @@ func (h *history) Undo(ctx session.Context) (info HistoryInfo, err error) {
}
if action.Details != nil {
s.SetDetails(pbtypes.CopyStruct(action.Details.Before, false))
s.SetDetails(action.Details.Before.Copy())
}
if err = h.Apply(s, smartblock.NoHistory, smartblock.NoRestrictions); err != nil {
return
@ -82,7 +81,7 @@ func (h *history) Redo(ctx session.Context) (info HistoryInfo, err error) {
s.SetObjectTypeKeys(ot)
}
if action.Details != nil {
s.SetDetails(pbtypes.CopyStruct(action.Details.After, true))
s.SetDetails(action.Details.After.Copy())
}
if err = h.Apply(s, smartblock.NoHistory, smartblock.NoRestrictions); err != nil {
return

View file

@ -4,29 +4,25 @@ import (
"strings"
"testing"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock/smarttest"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
func TestHistory_Undo(t *testing.T) {
t.Run("basic", func(t *testing.T) {
bDetails := &types.Struct{
Fields: map[string]*types.Value{
"beforeK": pbtypes.String("beforeV"),
},
}
aDetails := &types.Struct{
Fields: map[string]*types.Value{
"afterK": pbtypes.String("afterV"),
},
}
bDetails := domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
"beforeK": domain.String("beforeV"),
})
aDetails := domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
"afterK": domain.String("afterV"),
})
sb := smarttest.New("test")
sb.AddBlock(simple.New(&model.Block{Id: "test", ChildrenIds: []string{"2"}})).
AddBlock(simple.New(&model.Block{Id: "2"}))
@ -55,7 +51,7 @@ func TestHistory_Undo(t *testing.T) {
s.Unlink("3")
require.NoError(t, s.InsertTo("2", model.Block_Right, "3"))
require.NoError(t, sb.Apply(s))
//t.Log(sb.Doc.(*state.State).String())
// t.Log(sb.Doc.(*state.State).String())
s = sb.NewState()
s.Unlink("3")
@ -66,7 +62,7 @@ func TestHistory_Undo(t *testing.T) {
_, err := h.Undo(nil)
require.NoError(t, err)
//t.Log(sb.Doc.(*state.State).String())
// t.Log(sb.Doc.(*state.State).String())
require.Len(t, sb.Doc.Pick("test").Model().ChildrenIds, 1)
assert.True(t, strings.HasPrefix(sb.Doc.Pick("test").Model().ChildrenIds[0], "r-"))
})

View file

@ -5,13 +5,13 @@ import (
"fmt"
"github.com/globalsign/mgo/bson"
"github.com/gogo/protobuf/types"
bookmarksvc "github.com/anyproto/anytype-heart/core/block/bookmark"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/block/simple/bookmark"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/domain/objectorigin"
"github.com/anyproto/anytype-heart/core/session"
"github.com/anyproto/anytype-heart/pb"
@ -41,7 +41,7 @@ type Bookmark interface {
}
type BookmarkService interface {
CreateBookmarkObject(ctx context.Context, spaceID string, details *types.Struct, getContent bookmarksvc.ContentFuture) (objectId string, newDetails *types.Struct, err error)
CreateBookmarkObject(ctx context.Context, spaceID string, details *domain.Details, getContent bookmarksvc.ContentFuture) (objectId string, newDetails *domain.Details, err error)
FetchAsync(spaceID string, blockID string, params bookmark.FetchParams)
}

View file

@ -83,7 +83,7 @@ func (s *storeObject) Init(ctx *smartblock.InitContext) error {
if err != nil {
return err
}
s.subscription = newSubscription(s.Id(), s.eventSender)
s.subscription = newSubscription(s.SpaceID(), s.Id(), s.eventSender)
stateStore, err := storestate.New(ctx.Ctx, s.Id(), s.crdtDb, ChatHandler{
subscription: s.subscription,
@ -322,11 +322,7 @@ func (s *storeObject) SubscribeLastMessages(ctx context.Context, limit int) ([]*
return messages[i].OrderId < messages[j].OrderId
})
var firstOrderId string
if len(messages) > 0 {
firstOrderId = messages[0].OrderId
}
s.subscription.subscribe(firstOrderId)
s.subscription.enable()
return messages, 0, nil
}

View file

@ -10,6 +10,7 @@ import (
)
type subscription struct {
spaceId string
chatId string
eventSender event.Sender
@ -17,19 +18,18 @@ type subscription struct {
eventsBuffer []*pb.EventMessage
firstOrderId string
enabled bool
enabled bool
}
func newSubscription(chatId string, eventSender event.Sender) *subscription {
func newSubscription(spaceId string, chatId string, eventSender event.Sender) *subscription {
return &subscription{
spaceId: spaceId,
chatId: chatId,
eventSender: eventSender,
}
}
func (s *subscription) subscribe(firstOrderId string) {
s.firstOrderId = firstOrderId
func (s *subscription) enable() {
s.enabled = true
}
@ -63,7 +63,7 @@ func (s *subscription) flush() {
}
func (s *subscription) add(message *model.ChatMessage) {
if !s.canSend(message) {
if !s.canSend() {
return
}
ev := &pb.EventChatAdd{
@ -71,63 +71,52 @@ func (s *subscription) add(message *model.ChatMessage) {
Message: message,
OrderId: message.OrderId,
}
s.eventsBuffer = append(s.eventsBuffer, &pb.EventMessage{
Value: &pb.EventMessageValueOfChatAdd{
ChatAdd: ev,
},
})
s.eventsBuffer = append(s.eventsBuffer, event.NewMessage(s.spaceId, &pb.EventMessageValueOfChatAdd{
ChatAdd: ev,
}))
}
func (s *subscription) delete(messageId string) {
ev := &pb.EventChatDelete{
Id: messageId,
}
s.eventsBuffer = append(s.eventsBuffer, &pb.EventMessage{
Value: &pb.EventMessageValueOfChatDelete{
ChatDelete: ev,
},
})
s.eventsBuffer = append(s.eventsBuffer, event.NewMessage(s.spaceId, &pb.EventMessageValueOfChatDelete{
ChatDelete: ev,
}))
}
func (s *subscription) updateFull(message *model.ChatMessage) {
if !s.canSend(message) {
if !s.canSend() {
return
}
ev := &pb.EventChatUpdate{
Id: message.Id,
Message: message,
}
s.eventsBuffer = append(s.eventsBuffer, &pb.EventMessage{
Value: &pb.EventMessageValueOfChatUpdate{
ChatUpdate: ev,
},
})
s.eventsBuffer = append(s.eventsBuffer, event.NewMessage(s.spaceId, &pb.EventMessageValueOfChatUpdate{
ChatUpdate: ev,
}))
}
func (s *subscription) updateReactions(message *model.ChatMessage) {
if !s.canSend(message) {
if !s.canSend() {
return
}
ev := &pb.EventChatUpdateReactions{
Id: message.Id,
Reactions: message.Reactions,
}
s.eventsBuffer = append(s.eventsBuffer, &pb.EventMessage{
Value: &pb.EventMessageValueOfChatUpdateReactions{
ChatUpdateReactions: ev,
},
})
s.eventsBuffer = append(s.eventsBuffer, event.NewMessage(s.spaceId, &pb.EventMessageValueOfChatUpdateReactions{
ChatUpdateReactions: ev,
}))
}
func (s *subscription) canSend(message *model.ChatMessage) bool {
func (s *subscription) canSend() bool {
if s.sessionContext != nil {
return true
}
if !s.enabled {
return false
}
if s.firstOrderId > message.OrderId {
return false
}
return true
}

View file

@ -448,13 +448,13 @@ func (cb *clipboard) pasteAny(
}
relationLinks := destState.GetRelationLinks()
var missingRelationKeys []string
var missingRelationKeys []domain.RelationKey
// collect missing relation keys to add it to state
for _, b := range s.Blocks() {
if r := b.GetRelation(); r != nil {
if !relationLinks.Has(r.Key) {
missingRelationKeys = append(missingRelationKeys, r.Key)
missingRelationKeys = append(missingRelationKeys, domain.RelationKey(r.Key))
}
}
}
@ -570,9 +570,9 @@ func (cb *clipboard) addRelationLinksToDataview(d *model.BlockContentDataview) (
return
}
relationKeysList := make([]string, len(relationKeys))
relationKeysList := make([]domain.RelationKey, 0, len(relationKeys))
for k := range relationKeys {
relationKeysList = append(relationKeysList, k)
relationKeysList = append(relationKeysList, domain.RelationKey(k))
}
relations, err := cb.objectStore.FetchRelationByKeys(relationKeysList...)
if err != nil {

View file

@ -547,7 +547,7 @@ func TestClipboard_TitleOps(t *testing.T) {
s.Add(tb)
s.InsertTo("", 0, tb.Model().Id)
}
_, _, err := state.ApplyState(s, false)
_, _, err := state.ApplyState("", s, false)
require.NoError(t, err)
return sb
}
@ -572,7 +572,7 @@ func TestClipboard_TitleOps(t *testing.T) {
bm.Model().Id = "bookmarkId"
s.Add(bm)
s.InsertTo("", 0, bm.Model().Id)
_, _, err := state.ApplyState(s, false)
_, _, err := state.ApplyState("", s, false)
require.NoError(t, err)
return sb
}
@ -1103,7 +1103,7 @@ func addDescription(st *smarttest.SmartTest, description string) {
newState := st.Doc.NewState()
template.InitTemplate(newState, template.WithForcedDescription)
newState.Get(template.DescriptionBlockId).(text.Block).SetText(description, nil)
state.ApplyState(newState, false)
state.ApplyState("", newState, false)
}
func addRelations(st *smarttest.SmartTest) {
@ -1111,7 +1111,7 @@ func addRelations(st *smarttest.SmartTest) {
template.InitTemplate(newState, template.RequireHeader)
template.InitTemplate(newState, template.WithFeaturedRelations)
template.InitTemplate(newState, template.WithForcedDescription)
state.ApplyState(newState, false)
state.ApplyState("", newState, false)
}
func TestClipboard_PasteToCodeBlock(t *testing.T) {

View file

@ -5,10 +5,10 @@ import (
"fmt"
"github.com/anyproto/any-sync/app/ocache"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
)
@ -26,7 +26,7 @@ type Collection interface {
GetIds() (ids []string, err error)
ModifyLocalDetails(
objectId string,
modifier func(current *types.Struct) (*types.Struct, error),
modifier func(current *domain.Details) (*domain.Details, error),
) (err error)
}
@ -111,7 +111,7 @@ func (p *objectLinksCollection) GetIds() (ids []string, err error) {
// and if it is not found, sets pending details in object store
func (p *objectLinksCollection) ModifyLocalDetails(
objectId string,
modifier func(current *types.Struct) (*types.Struct, error),
modifier func(current *domain.Details) (*domain.Details, error),
) (err error) {
if modifier == nil {
return fmt.Errorf("modifier is nil")
@ -126,7 +126,7 @@ func (p *objectLinksCollection) ModifyLocalDetails(
return err
}
err = p.Space().Do(objectId, func(b smartblock.SmartBlock) error {
// we just need to invoke the smartblock so it reads from pending details
// we just need to invoke the smartblock, so it reads from pending details
// no need to call modify twice
if err == nil {
return b.Apply(b.NewState())

View file

@ -17,7 +17,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"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"
)
@ -135,7 +134,7 @@ func (c *layoutConverter) fromNoteToSet(st *state.State) error {
}
func (c *layoutConverter) fromAnyToSet(st *state.State) error {
source := pbtypes.GetStringList(st.Details(), bundle.RelationKeySetOf.String())
source := st.Details().GetStringList(bundle.RelationKeySetOf)
addFeaturedRelationSetOf(st)
dvBlock, err := dataview.BlockBySource(c.objectStore.SpaceIndex(st.SpaceID()), source)
@ -147,11 +146,11 @@ func (c *layoutConverter) fromAnyToSet(st *state.State) error {
}
func addFeaturedRelationSetOf(st *state.State) {
fr := pbtypes.GetStringList(st.Details(), bundle.RelationKeyFeaturedRelations.String())
fr := st.Details().GetStringList(bundle.RelationKeyFeaturedRelations)
if !slices.Contains(fr, bundle.RelationKeySetOf.String()) {
fr = append(fr, bundle.RelationKeySetOf.String())
}
st.SetDetail(bundle.RelationKeyFeaturedRelations.String(), pbtypes.StringList(fr))
st.SetDetail(bundle.RelationKeyFeaturedRelations, domain.StringList(fr))
}
func (c *layoutConverter) fromSetToCollection(st *state.State) error {
@ -160,7 +159,7 @@ func (c *layoutConverter) fromSetToCollection(st *state.State) error {
return fmt.Errorf("dataview block is not found")
}
details := st.Details()
setSourceIds := pbtypes.GetStringList(details, bundle.RelationKeySetOf.String())
setSourceIds := details.GetStringList(bundle.RelationKeySetOf)
spaceId := st.SpaceID()
c.removeRelationSetOf(st)
@ -194,7 +193,7 @@ func (c *layoutConverter) listIDsFromSet(spaceID string, typesFromSet []string)
}
ids := make([]string, 0, len(records))
for _, record := range records {
ids = append(ids, pbtypes.GetString(record.Details, bundle.RelationKeyId.String()))
ids = append(ids, record.Details.GetString(bundle.RelationKeyId))
}
return ids, nil
}
@ -218,9 +217,9 @@ func (c *layoutConverter) fromAnyToCollection(st *state.State) error {
}
func (c *layoutConverter) fromNoteToAny(st *state.State) error {
name, ok := st.Details().Fields[bundle.RelationKeyName.String()]
name, ok := st.Details().TryString(bundle.RelationKeyName)
if !ok || name.GetStringValue() == "" {
if !ok || name == "" {
textBlock, err := getFirstTextBlock(st)
if err != nil {
return err
@ -228,7 +227,7 @@ func (c *layoutConverter) fromNoteToAny(st *state.State) error {
if textBlock == nil {
return nil
}
st.SetDetail(bundle.RelationKeyName.String(), pbtypes.String(textBlock.Model().GetText().GetText()))
st.SetDetail(bundle.RelationKeyName, domain.String(textBlock.Model().GetText().GetText()))
for _, id := range textBlock.Model().ChildrenIds {
st.Unlink(id)
@ -252,11 +251,11 @@ func (c *layoutConverter) fromAnyToNote(st *state.State) error {
}
func (c *layoutConverter) removeRelationSetOf(st *state.State) {
st.RemoveDetail(bundle.RelationKeySetOf.String())
st.RemoveDetail(bundle.RelationKeySetOf)
fr := pbtypes.GetStringList(st.Details(), bundle.RelationKeyFeaturedRelations.String())
fr := st.Details().GetStringList(bundle.RelationKeyFeaturedRelations)
fr = slice.RemoveMut(fr, bundle.RelationKeySetOf.String())
st.SetDetail(bundle.RelationKeyFeaturedRelations.String(), pbtypes.StringList(fr))
st.SetDetail(bundle.RelationKeyFeaturedRelations, domain.StringList(fr))
}
func getFirstTextBlock(st *state.State) (simple.Block, error) {
@ -274,8 +273,8 @@ func getFirstTextBlock(st *state.State) (simple.Block, error) {
return res, nil
}
func (c *layoutConverter) generateFilters(spaceId string, typesAndRelations []string) ([]*model.BlockContentDataviewFilter, error) {
var filters []*model.BlockContentDataviewFilter
func (c *layoutConverter) generateFilters(spaceId string, typesAndRelations []string) ([]database.FilterRequest, error) {
var filters []database.FilterRequest
m, err := c.sbtProvider.PartitionIDsByType(spaceId, typesAndRelations)
if err != nil {
return nil, fmt.Errorf("partition ids by sb type: %w", err)
@ -288,26 +287,26 @@ func (c *layoutConverter) generateFilters(spaceId string, typesAndRelations []st
return filters, nil
}
func (c *layoutConverter) appendRelationFilters(spaceId string, relationIDs []string, filters []*model.BlockContentDataviewFilter) ([]*model.BlockContentDataviewFilter, error) {
func (c *layoutConverter) appendRelationFilters(spaceId string, relationIDs []string, filters []database.FilterRequest) ([]database.FilterRequest, error) {
for _, relationID := range relationIDs {
relation, err := c.objectStore.SpaceIndex(spaceId).GetRelationById(relationID)
if err != nil {
return nil, fmt.Errorf("get relation by id %s: %w", relationID, err)
}
filters = append(filters, &model.BlockContentDataviewFilter{
RelationKey: relation.Key,
filters = append(filters, database.FilterRequest{
RelationKey: domain.RelationKey(relation.Key),
Condition: model.BlockContentDataviewFilter_Exists,
})
}
return filters, nil
}
func (c *layoutConverter) appendTypesFilter(types []string, filters []*model.BlockContentDataviewFilter) []*model.BlockContentDataviewFilter {
func (c *layoutConverter) appendTypesFilter(types []string, filters []database.FilterRequest) []database.FilterRequest {
if len(types) != 0 {
filters = append(filters, &model.BlockContentDataviewFilter{
RelationKey: bundle.RelationKeyType.String(),
filters = append(filters, database.FilterRequest{
RelationKey: bundle.RelationKeyType,
Condition: model.BlockContentDataviewFilter_In,
Value: pbtypes.StringList(types),
Value: domain.StringList(types),
})
}
return filters

View file

@ -4,18 +4,17 @@ import (
"fmt"
"testing"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/editor/template"
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
const (
@ -26,9 +25,9 @@ const (
func TestLayoutConverter_Convert(t *testing.T) {
store := objectstore.NewStoreFixture(t)
store.AddObjects(t, spaceId, []spaceindex.TestObject{{
bundle.RelationKeyId: pbtypes.String(bundle.TypeKeyTask.URL()),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyUniqueKey: pbtypes.String(bundle.TypeKeyTask.URL()),
bundle.RelationKeyId: domain.String(bundle.TypeKeyTask.URL()),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyUniqueKey: domain.String(bundle.TypeKeyTask.URL()),
}})
for _, from := range []model.ObjectTypeLayout{
@ -43,12 +42,10 @@ func TestLayoutConverter_Convert(t *testing.T) {
st := state.NewDoc(root, map[string]simple.Block{
root: simple.New(&model.Block{Id: root, ChildrenIds: []string{}}),
}).NewState()
st.SetDetails(&types.Struct{
Fields: map[string]*types.Value{
bundle.RelationKeySpaceId.String(): pbtypes.String(spaceId),
bundle.RelationKeySetOf.String(): pbtypes.StringList([]string{bundle.TypeKeyTask.URL()}),
},
})
st.SetDetails(domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeySetOf: domain.StringList([]string{bundle.TypeKeyTask.URL()}),
}))
lc := layoutConverter{objectStore: store}

View file

@ -5,7 +5,6 @@ import (
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/editor/basic"
"github.com/anyproto/anytype-heart/core/block/editor/collection"
@ -19,7 +18,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/database"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)
@ -64,7 +62,7 @@ func (p *Dashboard) CreationStateMigration(ctx *smartblock.InitContext) migratio
template.WithDetailName("Home"),
template.WithDetailIconEmoji("🏠"),
template.WithNoDuplicateLinks(),
template.WithForcedDetail(bundle.RelationKeyIsHidden, pbtypes.Bool(true)),
template.WithForcedDetail(bundle.RelationKeyIsHidden, domain.Bool(true)),
)
},
}
@ -73,7 +71,7 @@ func (p *Dashboard) CreationStateMigration(ctx *smartblock.InitContext) migratio
func (p *Dashboard) StateMigrations() migration.Migrations {
return migration.MakeMigrations([]migration.Migration{{
Version: 2,
Proc: template.WithForcedDetail(bundle.RelationKeyIsHidden, pbtypes.Bool(true)),
Proc: template.WithForcedDetail(bundle.RelationKeyIsHidden, domain.Bool(true)),
}})
}
@ -94,11 +92,11 @@ func (p *Dashboard) updateObjects(info smartblock.ApplyInfo) (err error) {
func (p *Dashboard) updateInStore(favoritedIds []string) error {
records, err := p.objectStore.Query(database.Query{
Filters: []*model.BlockContentDataviewFilter{
Filters: []database.FilterRequest{
{
RelationKey: bundle.RelationKeyIsFavorite.String(),
RelationKey: bundle.RelationKeyIsFavorite,
Condition: model.BlockContentDataviewFilter_Equal,
Value: pbtypes.Bool(true),
Value: domain.Bool(true),
},
},
})
@ -107,19 +105,17 @@ func (p *Dashboard) updateInStore(favoritedIds []string) error {
}
var storeFavoritedIds = make([]string, 0, len(records))
for _, rec := range records {
storeFavoritedIds = append(storeFavoritedIds, pbtypes.GetString(rec.Details, bundle.RelationKeyId.String()))
storeFavoritedIds = append(storeFavoritedIds, rec.Details.GetString(bundle.RelationKeyId))
}
removedIds, addedIds := slice.DifferenceRemovedAdded(storeFavoritedIds, favoritedIds)
for _, removedId := range removedIds {
go func(id string) {
if err := p.ModifyLocalDetails(id, func(current *types.Struct) (*types.Struct, error) {
if current == nil || current.Fields == nil {
current = &types.Struct{
Fields: map[string]*types.Value{},
}
if err := p.ModifyLocalDetails(id, func(current *domain.Details) (*domain.Details, error) {
if current == nil {
current = domain.NewDetails()
}
current.Fields[bundle.RelationKeyIsFavorite.String()] = pbtypes.Bool(false)
current.SetBool(bundle.RelationKeyIsFavorite, false)
return current, nil
}); err != nil {
logFavoriteError(err)
@ -128,13 +124,11 @@ func (p *Dashboard) updateInStore(favoritedIds []string) error {
}
for _, addedId := range addedIds {
go func(id string) {
if err := p.ModifyLocalDetails(id, func(current *types.Struct) (*types.Struct, error) {
if current == nil || current.Fields == nil {
current = &types.Struct{
Fields: map[string]*types.Value{},
}
if err := p.ModifyLocalDetails(id, func(current *domain.Details) (*domain.Details, error) {
if current == nil {
current = domain.NewDetails()
}
current.Fields[bundle.RelationKeyIsFavorite.String()] = pbtypes.Bool(true)
current.SetBool(bundle.RelationKeyIsFavorite, true)
return current, nil
}); err != nil {
logFavoriteError(err)

View file

@ -22,7 +22,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/internalflag"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)
@ -90,7 +89,7 @@ func (d *sdataview) SetSource(ctx session.Context, blockId string, source []stri
if len(source) == 0 {
s.Unlink(blockId)
s.SetLocalDetail(bundle.RelationKeySetOf.String(), pbtypes.StringList(source))
s.SetLocalDetail(bundle.RelationKeySetOf, domain.StringList(source))
return d.Apply(s, smartblock.NoRestrictions, smartblock.KeepInternalFlags)
}
@ -108,7 +107,7 @@ func (d *sdataview) SetSource(ctx session.Context, blockId string, source []stri
s.InsertTo("", 0, blockId)
}
s.SetLocalDetail(bundle.RelationKeySetOf.String(), pbtypes.StringList(source))
s.SetLocalDetail(bundle.RelationKeySetOf, domain.StringList(source))
return d.Apply(s, smartblock.NoRestrictions, smartblock.KeepInternalFlags)
}
@ -127,7 +126,7 @@ func (d *sdataview) SetSourceInSet(ctx session.Context, source []string) (err er
return fmt.Errorf("failed to update view '%s' of set '%s': %w", view.Id, s.RootId(), err)
}
}
s.SetDetailAndBundledRelation(bundle.RelationKeySetOf, pbtypes.StringList(source))
s.SetDetailAndBundledRelation(bundle.RelationKeySetOf, domain.StringList(source))
flags := internalflag.NewFromState(s)
// set with source is no longer empty

View file

@ -13,12 +13,12 @@ import (
"github.com/anyproto/anytype-heart/core/block/editor/template"
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/block/simple/dataview"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/session"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)
@ -148,14 +148,14 @@ func TestDataview_SetSource(t *testing.T) {
fx.store.AddObjects(t, []objectstore.TestObject{
{
bundle.RelationKeySpaceId: pbtypes.String(spcId),
bundle.RelationKeyId: pbtypes.String("rel-id"),
bundle.RelationKeyRelationKey: pbtypes.String("id"),
bundle.RelationKeySpaceId: domain.String(spcId),
bundle.RelationKeyId: domain.String("rel-id"),
bundle.RelationKeyRelationKey: domain.String("id"),
},
{
bundle.RelationKeySpaceId: pbtypes.String(spcId),
bundle.RelationKeyId: pbtypes.String("rel-name"),
bundle.RelationKeyRelationKey: pbtypes.String("name"),
bundle.RelationKeySpaceId: domain.String(spcId),
bundle.RelationKeyId: domain.String("rel-name"),
bundle.RelationKeyRelationKey: domain.String("name"),
},
})
@ -164,7 +164,7 @@ func TestDataview_SetSource(t *testing.T) {
// then
assert.NoError(t, err)
setOf := pbtypes.GetStringList(fx.sb.LocalDetails(), bundle.RelationKeySetOf.String())
setOf := fx.sb.CombinedDetails().GetStringList(bundle.RelationKeySetOf)
require.Len(t, setOf, 2)
assert.True(t, slice.UnsortedEqual(setOf, source))
@ -181,9 +181,9 @@ func TestDataview_SetSource(t *testing.T) {
fx.sb.AddBlock(simple.New(&model.Block{Id: "dv", Content: &model.BlockContentOfDataview{Dataview: &model.BlockContentDataview{
Source: []string{"ot-bookmark"},
}}}))
err := fx.sb.SetDetails(nil, []*model.Detail{{
Key: bundle.RelationKeySetOf.String(),
Value: pbtypes.StringList([]string{"ot-bookmark"}),
err := fx.sb.SetDetails(nil, []domain.Detail{{
Key: bundle.RelationKeySetOf,
Value: domain.StringList([]string{"ot-bookmark"}),
}}, false)
require.NoError(t, err)
@ -192,7 +192,7 @@ func TestDataview_SetSource(t *testing.T) {
// then
assert.NoError(t, err)
setOf := pbtypes.GetStringList(fx.sb.LocalDetails(), bundle.RelationKeySetOf.String())
setOf := fx.sb.CombinedDetails().GetStringList(bundle.RelationKeySetOf)
assert.Len(t, setOf, 0)
block := fx.sb.Pick("dv")
@ -209,12 +209,12 @@ func TestDataview_SetSourceInSet(t *testing.T) {
{DefaultObjectTypeId: "ot-note", DefaultTemplateId: "NoTe"},
{DefaultObjectTypeId: "ot-task", DefaultTemplateId: "tAsK"},
}}}}))
err := fx.sb.SetDetails(nil, []*model.Detail{{
Key: bundle.RelationKeySetOf.String(),
Value: pbtypes.StringList([]string{"rel-name", "rel-id"}),
err := fx.sb.SetDetails(nil, []domain.Detail{{
Key: bundle.RelationKeySetOf,
Value: domain.StringList([]string{"rel-name", "rel-id"}),
}, {
Key: bundle.RelationKeyInternalFlags.String(),
Value: pbtypes.IntList(int(model.InternalFlag_editorDeleteEmpty)),
Key: bundle.RelationKeyInternalFlags,
Value: domain.Int64List([]int64{int64(model.InternalFlag_editorDeleteEmpty)}),
}}, false)
require.NoError(t, err)
@ -223,7 +223,7 @@ func TestDataview_SetSourceInSet(t *testing.T) {
// then
assert.NoError(t, err)
setOf := pbtypes.GetStringList(fx.sb.NewState().Details(), bundle.RelationKeySetOf.String())
setOf := fx.sb.NewState().Details().GetStringList(bundle.RelationKeySetOf)
require.Len(t, setOf, 1)
assert.Equal(t, "ot-page", setOf[0])
@ -237,7 +237,7 @@ func TestDataview_SetSourceInSet(t *testing.T) {
assert.Empty(t, dv.Views[1].DefaultTemplateId)
assert.Empty(t, dv.Views[1].DefaultObjectTypeId)
assert.Empty(t, pbtypes.GetIntList(fx.sb.NewState().Details(), bundle.RelationKeyInternalFlags.String()))
assert.Empty(t, fx.sb.NewState().Details().GetInt64List(bundle.RelationKeyInternalFlags))
})
// TODO: GO-4189 Add more tests when more logic on SetSourceToSet will be added

View file

@ -20,6 +20,7 @@ import (
"github.com/anyproto/anytype-heart/core/block/process"
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/block/simple/file"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/domain/objectorigin"
"github.com/anyproto/anytype-heart/core/files/fileuploader"
"github.com/anyproto/anytype-heart/core/session"
@ -48,7 +49,7 @@ func NewFile(sb smartblock.SmartBlock, blockService BlockService, picker cache.O
}
type BlockService interface {
CreateLinkToTheNewObject(ctx context.Context, sctx session.Context, req *pb.RpcBlockLinkCreateWithObjectRequest) (linkID string, pageID string, details *types.Struct, err error)
CreateLinkToTheNewObject(ctx context.Context, sctx session.Context, req *pb.RpcBlockLinkCreateWithObjectRequest) (linkID string, pageID string, details *domain.Details, err error)
}
type File interface {
@ -125,7 +126,7 @@ func (sf *sfile) SetFileTargetObjectId(ctx session.Context, blockId, targetObjec
return err
}
var blockContentFileType model.BlockContentFileType
switch model.ObjectTypeLayout(pbtypes.GetInt64(sb.Details(), bundle.RelationKeyLayout.String())) {
switch model.ObjectTypeLayout(sb.Details().GetInt64(bundle.RelationKeyLayout)) {
case model.ObjectType_image:
blockContentFileType = model.BlockContentFile_Image
case model.ObjectType_audio:

View file

@ -10,7 +10,6 @@ import (
"github.com/anyproto/any-sync/accountservice/mock_accountservice"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonfile/fileservice"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
@ -22,6 +21,7 @@ import (
"github.com/anyproto/anytype-heart/core/block/editor/template"
"github.com/anyproto/anytype-heart/core/block/process"
"github.com/anyproto/anytype-heart/core/block/restriction"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/event/mock_event"
"github.com/anyproto/anytype-heart/core/files"
"github.com/anyproto/anytype-heart/core/files/fileobject/mock_fileobject"
@ -40,7 +40,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/tests/blockbuilder"
"github.com/anyproto/anytype-heart/tests/testutil"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
type fileFixture struct {
@ -110,9 +109,9 @@ func TestFile(t *testing.T) {
// given
fx := newFixture(t)
fileSb := smarttest.New("root")
fileSb.SetDetails(nil, []*model.Detail{{
Key: bundle.RelationKeyLayout.String(),
Value: pbtypes.Int64(int64(testCase.typeLayout)),
fileSb.SetDetails(nil, []domain.Detail{{
Key: bundle.RelationKeyLayout,
Value: domain.Int64(int64(testCase.typeLayout)),
}}, false)
fx.pickerFx.EXPECT().GetObject(mock.Anything, "testObjId").Return(fileSb, nil)
@ -161,12 +160,12 @@ func TestDropFiles(t *testing.T) {
fx := newFixture(t)
st := fx.sb.Doc.NewState()
st.SetDetail(bundle.RelationKeyLayout.String(), pbtypes.Int64(int64(model.ObjectType_collection)))
st.SetDetail(bundle.RelationKeyLayout, domain.Int64(int64(model.ObjectType_collection)))
fx.sb.Doc = st
fx.pickerFx.EXPECT().GetObject(context.Background(), "root").Return(fx, nil).Maybe()
fx.mockSender.EXPECT().Broadcast(mock.Anything).Return().Maybe()
mockService := mock_fileobject.NewMockService(t)
mockService.EXPECT().Create(mock.Anything, mock.Anything, mock.Anything).Return("fileObjectId", &types.Struct{Fields: map[string]*types.Value{}}, nil).Maybe()
mockService.EXPECT().Create(mock.Anything, mock.Anything, mock.Anything).Return("fileObjectId", domain.NewDetails(), nil).Maybe()
fx.fileUploaderFactory = prepareFileService(t, fx.mockSender, mockService)
// when
@ -186,12 +185,12 @@ func TestDropFiles(t *testing.T) {
fx := newFixture(t)
st := fx.sb.Doc.NewState()
st.SetDetail(bundle.RelationKeyLayout.String(), pbtypes.Int64(int64(model.ObjectType_collection)))
st.SetDetail(bundle.RelationKeyLayout, domain.Int64(int64(model.ObjectType_collection)))
fx.sb.Doc = st
fx.pickerFx.EXPECT().GetObject(context.Background(), "root").Return(fx, nil).Maybe()
fx.mockSender.EXPECT().Broadcast(mock.Anything).Return().Maybe()
mockService := mock_fileobject.NewMockService(t)
mockService.EXPECT().Create(mock.Anything, mock.Anything, mock.Anything).Return("fileObjectId", &types.Struct{Fields: map[string]*types.Value{}}, nil).Maybe()
mockService.EXPECT().Create(mock.Anything, mock.Anything, mock.Anything).Return("fileObjectId", domain.NewDetails(), nil).Maybe()
fx.fileUploaderFactory = prepareFileService(t, fx.mockSender, mockService)
// when
@ -211,12 +210,12 @@ func TestDropFiles(t *testing.T) {
fx := newFixture(t)
st := fx.sb.Doc.NewState()
st.SetDetail(bundle.RelationKeyLayout.String(), pbtypes.Int64(int64(model.ObjectType_collection)))
st.SetDetail(bundle.RelationKeyLayout, domain.Int64(int64(model.ObjectType_collection)))
fx.sb.Doc = st
fx.pickerFx.EXPECT().GetObject(context.Background(), "root").Return(fx, nil)
fx.mockSender.EXPECT().Broadcast(mock.Anything).Return()
mockService := mock_fileobject.NewMockService(t)
mockService.EXPECT().Create(context.Background(), "", mock.Anything).Return("fileObjectId", &types.Struct{Fields: map[string]*types.Value{}}, nil).Maybe()
mockService.EXPECT().Create(context.Background(), "", mock.Anything).Return("fileObjectId", domain.NewDetails(), nil).Maybe()
fx.fileUploaderFactory = prepareFileService(t, fx.mockSender, mockService)
// when
@ -246,12 +245,12 @@ func TestDropFiles(t *testing.T) {
fx := newFixture(t)
st := fx.sb.Doc.NewState()
st.SetDetail(bundle.RelationKeyLayout.String(), pbtypes.Int64(int64(model.ObjectType_collection)))
st.SetDetail(bundle.RelationKeyLayout, domain.Int64(int64(model.ObjectType_collection)))
fx.sb.Doc = st
fx.pickerFx.EXPECT().GetObject(context.Background(), "root").Return(fx, nil)
fx.mockSender.EXPECT().Broadcast(mock.Anything).Return()
mockService := mock_fileobject.NewMockService(t)
mockService.EXPECT().Create(context.Background(), "", mock.Anything).Return("fileObjectId", &types.Struct{Fields: map[string]*types.Value{}}, nil).Maybe()
mockService.EXPECT().Create(context.Background(), "", mock.Anything).Return("fileObjectId", domain.NewDetails(), nil).Maybe()
fx.fileUploaderFactory = prepareFileService(t, fx.mockSender, mockService)
// when

View file

@ -4,8 +4,6 @@ import (
"context"
"fmt"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/editor/basic"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/state"
@ -108,10 +106,10 @@ func (f *File) InjectVirtualBlocks(objectId string, view *model.ObjectView) {
return
}
var details *types.Struct
var details *domain.Details
for _, det := range view.Details {
if det.Id == objectId {
details = det.Details
details = domain.NewDetailsFromProto(det.Details)
break
}
}

View file

@ -10,7 +10,6 @@ import (
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/app/logger"
"github.com/cheggaaa/mb/v3"
"github.com/gogo/protobuf/types"
"go.uber.org/zap"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
@ -21,7 +20,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/space/clientspace"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
const (
@ -174,14 +172,14 @@ func (u *updater) updateLastUsedDate(spc clientspace.Space, key Key, ts int64) e
return fmt.Errorf("failed to get details: %w", err)
}
id := pbtypes.GetString(details.Details, bundle.RelationKeyId.String())
id := details.GetString(bundle.RelationKeyId)
if id == "" {
return fmt.Errorf("failed to get id from details: %w", err)
}
if err = spc.DoCtx(u.ctx, id, func(sb smartblock.SmartBlock) error {
st := sb.NewState()
st.SetLocalDetail(bundle.RelationKeyLastUsedDate.String(), pbtypes.Int64(ts))
st.SetLocalDetail(bundle.RelationKeyLastUsedDate, domain.Int64(ts))
return sb.Apply(st)
}); err != nil {
return fmt.Errorf("failed to set lastUsedDate to object: %w", err)
@ -189,8 +187,8 @@ func (u *updater) updateLastUsedDate(spc clientspace.Space, key Key, ts int64) e
return nil
}
func SetLastUsedDateForInitialObjectType(id string, details *types.Struct) {
if !strings.HasPrefix(id, addr.BundledObjectTypeURLPrefix) || details == nil || details.Fields == nil {
func SetLastUsedDateForInitialObjectType(id string, details *domain.Details) {
if !strings.HasPrefix(id, addr.BundledObjectTypeURLPrefix) || details == nil {
return
}
@ -212,5 +210,5 @@ func SetLastUsedDateForInitialObjectType(id string, details *types.Struct) {
// we do this trick to order crucial Anytype object types by last date
lastUsed := time.Now().Add(time.Duration(-1 * priority * int64(maxInstallationTime))).Unix()
details.Fields[bundle.RelationKeyLastUsedDate.String()] = pbtypes.Int64(lastUsed)
details.SetInt64(bundle.RelationKeyLastUsedDate, lastUsed)
}

View file

@ -6,7 +6,6 @@ import (
"testing"
"time"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
@ -18,12 +17,11 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/space/clientspace"
"github.com/anyproto/anytype-heart/space/clientspace/mock_clientspace"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
func TestSetLastUsedDateForInitialType(t *testing.T) {
isLastUsedDateGreater := func(details1, details2 *types.Struct) bool {
return pbtypes.GetInt64(details1, bundle.RelationKeyLastUsedDate.String()) > pbtypes.GetInt64(details2, bundle.RelationKeyLastUsedDate.String())
isLastUsedDateGreater := func(details1, details2 *domain.Details) bool {
return details1.GetInt64(bundle.RelationKeyLastUsedDate) > details2.GetInt64(bundle.RelationKeyLastUsedDate)
}
t.Run("object types are sorted by lastUsedDate in correct order", func(t *testing.T) {
@ -40,11 +38,11 @@ func TestSetLastUsedDateForInitialType(t *testing.T) {
rand.Shuffle(len(ots), func(i, j int) {
ots[i], ots[j] = ots[j], ots[i]
})
detailMap := map[string]*types.Struct{}
detailMap := map[string]*domain.Details{}
// when
for _, id := range ots {
details := &types.Struct{Fields: make(map[string]*types.Value)}
details := domain.NewDetails()
SetLastUsedDateForInitialObjectType(id, details)
detailMap[id] = details
}
@ -64,31 +62,31 @@ func TestUpdateLastUsedDate(t *testing.T) {
ts := time.Now().Unix()
isLastUsedDateRecent := func(details *types.Struct, deltaSeconds int64) bool {
return pbtypes.GetInt64(details, bundle.RelationKeyLastUsedDate.String())+deltaSeconds > time.Now().Unix()
isLastUsedDateRecent := func(details *domain.Details, deltaSeconds int64) bool {
return details.GetInt64(bundle.RelationKeyLastUsedDate)+deltaSeconds > time.Now().Unix()
}
store := objectstore.NewStoreFixture(t)
store.AddObjects(t, spaceId, []objectstore.TestObject{
{
bundle.RelationKeyId: pbtypes.String(bundle.RelationKeyCamera.URL()),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyUniqueKey: pbtypes.String(bundle.RelationKeyCamera.URL()),
bundle.RelationKeyId: domain.String(bundle.RelationKeyCamera.URL()),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyUniqueKey: domain.String(bundle.RelationKeyCamera.URL()),
},
{
bundle.RelationKeyId: pbtypes.String(bundle.TypeKeyDiaryEntry.URL()),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyUniqueKey: pbtypes.String(bundle.TypeKeyDiaryEntry.URL()),
bundle.RelationKeyId: domain.String(bundle.TypeKeyDiaryEntry.URL()),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyUniqueKey: domain.String(bundle.TypeKeyDiaryEntry.URL()),
},
{
bundle.RelationKeyId: pbtypes.String("rel-custom"),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyUniqueKey: pbtypes.String("rel-custom"),
bundle.RelationKeyId: domain.String("rel-custom"),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyUniqueKey: domain.String("rel-custom"),
},
{
bundle.RelationKeyId: pbtypes.String("opt-done"),
bundle.RelationKeySpaceId: pbtypes.String(spaceId),
bundle.RelationKeyUniqueKey: pbtypes.String("opt-done"),
bundle.RelationKeyId: domain.String("opt-done"),
bundle.RelationKeySpaceId: domain.String(spaceId),
bundle.RelationKeyUniqueKey: domain.String("opt-done"),
},
})

View file

@ -20,7 +20,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/database"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
var pageRequiredRelations = []domain.RelationKey{
@ -102,7 +101,7 @@ func (p *Page) Init(ctx *smartblock.InitContext) (err error) {
if p.isRelationDeleted(ctx) {
// todo: move this to separate component
go func() {
err = p.deleteRelationOptions(p.SpaceID(), pbtypes.GetString(p.Details(), bundle.RelationKeyRelationKey.String()))
err = p.deleteRelationOptions(p.SpaceID(), p.Details().GetString(bundle.RelationKeyRelationKey))
if err != nil {
log.With("err", err).Error("failed to delete relation options")
}
@ -113,21 +112,21 @@ func (p *Page) Init(ctx *smartblock.InitContext) (err error) {
func (p *Page) isRelationDeleted(ctx *smartblock.InitContext) bool {
return p.Type() == coresb.SmartBlockTypeRelation &&
pbtypes.GetBool(ctx.State.Details(), bundle.RelationKeyIsUninstalled.String())
ctx.State.Details().GetBool(bundle.RelationKeyIsUninstalled)
}
func (p *Page) deleteRelationOptions(spaceID string, relationKey string) error {
relationOptions, _, err := p.objectStore.QueryObjectIds(database.Query{
Filters: []*model.BlockContentDataviewFilter{
Filters: []database.FilterRequest{
{
RelationKey: bundle.RelationKeyRelationKey.String(),
RelationKey: bundle.RelationKeyRelationKey,
Condition: model.BlockContentDataviewFilter_Equal,
Value: pbtypes.String(relationKey),
Value: domain.String(relationKey),
},
{
RelationKey: bundle.RelationKeyLayout.String(),
RelationKey: bundle.RelationKeyLayout,
Condition: model.BlockContentDataviewFilter_Equal,
Value: pbtypes.Int64(int64(model.ObjectType_relationOption)),
Value: domain.Int64(model.ObjectType_relationOption),
},
},
})
@ -161,7 +160,7 @@ func (p *Page) CreationStateMigration(ctx *smartblock.InitContext) migration.Mig
if err != nil {
log.Errorf("failed to get object by unique key: %v", err)
} else {
layout = model.ObjectTypeLayout(pbtypes.GetInt64(otype.Details, bundle.RelationKeyRecommendedLayout.String()))
layout = model.ObjectTypeLayout(otype.GetInt64(bundle.RelationKeyRecommendedLayout))
}
}
}

View file

@ -3,8 +3,6 @@ package editor
import (
"time"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/editor/basic"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/template"
@ -13,7 +11,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/spaceinfo"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
var participantRequiredRelations = []domain.RelationKey{
@ -49,11 +46,11 @@ func (p *participant) Init(ctx *smartblock.InitContext) (err error) {
return
}
ctx.State.SetDetailAndBundledRelation(bundle.RelationKeyIsReadonly, pbtypes.Bool(true))
ctx.State.SetDetailAndBundledRelation(bundle.RelationKeyIsArchived, pbtypes.Bool(false))
ctx.State.SetDetailAndBundledRelation(bundle.RelationKeyIsHidden, pbtypes.Bool(false))
ctx.State.SetDetailAndBundledRelation(bundle.RelationKeyLayout, pbtypes.Int64(int64(model.ObjectType_participant)))
ctx.State.SetDetailAndBundledRelation(bundle.RelationKeyLayoutAlign, pbtypes.Int64(int64(model.Block_AlignCenter)))
ctx.State.SetDetailAndBundledRelation(bundle.RelationKeyIsReadonly, domain.Bool(true))
ctx.State.SetDetailAndBundledRelation(bundle.RelationKeyIsArchived, domain.Bool(false))
ctx.State.SetDetailAndBundledRelation(bundle.RelationKeyIsHidden, domain.Bool(false))
ctx.State.SetDetailAndBundledRelation(bundle.RelationKeyLayout, domain.Int64(model.ObjectType_participant))
ctx.State.SetDetailAndBundledRelation(bundle.RelationKeyLayoutAlign, domain.Int64(model.Block_AlignCenter))
records, err := p.objectStore.QueryByIds([]string{p.Id()})
if err != nil {
@ -73,23 +70,23 @@ func (p *participant) Init(ctx *smartblock.InitContext) (err error) {
return nil
}
func (p *participant) ModifyProfileDetails(profileDetails *types.Struct) (err error) {
details := pbtypes.CopyStructFields(profileDetails,
bundle.RelationKeyName.String(),
bundle.RelationKeyDescription.String(),
bundle.RelationKeyIconImage.String(),
bundle.RelationKeyGlobalName.String())
details.Fields[bundle.RelationKeyIdentityProfileLink.String()] = pbtypes.String(pbtypes.GetString(profileDetails, bundle.RelationKeyId.String()))
func (p *participant) ModifyProfileDetails(profileDetails *domain.Details) (err error) {
details := profileDetails.CopyOnlyKeys(
bundle.RelationKeyName,
bundle.RelationKeyDescription,
bundle.RelationKeyIconImage,
bundle.RelationKeyGlobalName,
)
details.SetString(bundle.RelationKeyIdentityProfileLink, profileDetails.GetString(bundle.RelationKeyId))
return p.modifyDetails(details)
}
func (p *participant) ModifyIdentityDetails(profile *model.IdentityProfile) (err error) {
details := &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyName.String(): pbtypes.String(profile.Name),
bundle.RelationKeyDescription.String(): pbtypes.String(profile.Description),
bundle.RelationKeyIconImage.String(): pbtypes.String(profile.IconCid),
bundle.RelationKeyGlobalName.String(): pbtypes.String(profile.GlobalName),
}}
details := domain.NewDetails()
details.SetString(bundle.RelationKeyName, profile.Name)
details.SetString(bundle.RelationKeyDescription, profile.Description)
details.SetString(bundle.RelationKeyIconImage, profile.IconCid)
details.SetString(bundle.RelationKeyGlobalName, profile.GlobalName)
return p.modifyDetails(details)
}
@ -102,9 +99,9 @@ func (p *participant) TryClose(objectTTL time.Duration) (bool, error) {
return false, nil
}
func (p *participant) modifyDetails(newDetails *types.Struct) (err error) {
return p.DetailsUpdatable.UpdateDetails(func(current *types.Struct) (*types.Struct, error) {
return pbtypes.StructMerge(current, newDetails, false), nil
func (p *participant) modifyDetails(newDetails *domain.Details) (err error) {
return p.DetailsUpdatable.UpdateDetails(func(current *domain.Details) (*domain.Details, error) {
return current.Merge(newDetails), nil
})
}
@ -114,14 +111,14 @@ func buildParticipantDetails(
identity string,
permissions model.ParticipantPermissions,
status model.ParticipantStatus,
) *types.Struct {
return &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyId.String(): pbtypes.String(id),
bundle.RelationKeyIdentity.String(): pbtypes.String(identity),
bundle.RelationKeySpaceId.String(): pbtypes.String(spaceId),
bundle.RelationKeyLastModifiedBy.String(): pbtypes.String(id),
bundle.RelationKeyParticipantPermissions.String(): pbtypes.Int64(int64(permissions)),
bundle.RelationKeyParticipantStatus.String(): pbtypes.Int64(int64(status)),
bundle.RelationKeyIsHiddenDiscovery.String(): pbtypes.Bool(status != model.ParticipantStatus_Active),
}}
) *domain.Details {
det := domain.NewDetails()
det.SetString(bundle.RelationKeyId, id)
det.SetString(bundle.RelationKeyIdentity, identity)
det.SetString(bundle.RelationKeySpaceId, spaceId)
det.SetString(bundle.RelationKeyLastModifiedBy, id)
det.SetInt64(bundle.RelationKeyParticipantPermissions, int64(permissions))
det.SetInt64(bundle.RelationKeyParticipantStatus, int64(status))
det.SetBool(bundle.RelationKeyIsHiddenDiscovery, status != model.ParticipantStatus_Active)
return det
}

View file

@ -17,19 +17,18 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/spaceinfo"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
func TestParticipant_ModifyProfileDetails(t *testing.T) {
// given
fx := newParticipantFixture(t)
defer fx.finish()
details := pbtypes.ToStruct(map[string]interface{}{
bundle.RelationKeyName.String(): "name",
bundle.RelationKeyDescription.String(): "description",
bundle.RelationKeyIconImage.String(): "icon",
bundle.RelationKeyId.String(): "profile",
bundle.RelationKeyGlobalName.String(): "global",
details := domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyName: domain.String("name"),
bundle.RelationKeyDescription: domain.String("description"),
bundle.RelationKeyIconImage: domain.String("icon"),
bundle.RelationKeyId: domain.String("profile"),
bundle.RelationKeyGlobalName: domain.String("global"),
})
// when
@ -37,14 +36,13 @@ func TestParticipant_ModifyProfileDetails(t *testing.T) {
// then
require.NoError(t, err)
details.Fields[bundle.RelationKeyIdentityProfileLink.String()] = pbtypes.String("profile")
delete(details.Fields, bundle.RelationKeyId.String())
fields := details.GetFields()
participantFields := fx.CombinedDetails().GetFields()
details.Set(bundle.RelationKeyIdentityProfileLink, domain.String("profile"))
details.Delete(bundle.RelationKeyId)
participantDetails := fx.CombinedDetails()
participantRelationLinks := fx.GetRelationLinks()
for key, _ := range details.Fields {
require.Equal(t, fields[key], participantFields[key])
require.True(t, participantRelationLinks.Has(key))
for key, _ := range details.Iterate() {
require.True(t, details.Get(key).Equal(participantDetails.Get(key)))
require.True(t, participantRelationLinks.Has(key.String()))
}
}
@ -64,21 +62,20 @@ func TestParticipant_ModifyParticipantAclState(t *testing.T) {
// then
require.NoError(t, err)
details := pbtypes.ToStruct(map[string]interface{}{
bundle.RelationKeyId.String(): "id",
bundle.RelationKeyIdentity.String(): "identity",
bundle.RelationKeySpaceId.String(): "spaceId",
bundle.RelationKeyLastModifiedBy.String(): "id",
bundle.RelationKeyParticipantPermissions.String(): model.ParticipantPermissions_Owner,
bundle.RelationKeyParticipantStatus.String(): model.ParticipantStatus_Active,
bundle.RelationKeyIsHiddenDiscovery.String(): false,
details := domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyId: domain.String("id"),
bundle.RelationKeyIdentity: domain.String("identity"),
bundle.RelationKeySpaceId: domain.String("spaceId"),
bundle.RelationKeyLastModifiedBy: domain.String("id"),
bundle.RelationKeyParticipantPermissions: domain.Int64(model.ParticipantPermissions_Owner),
bundle.RelationKeyParticipantStatus: domain.Int64(model.ParticipantStatus_Active),
bundle.RelationKeyIsHiddenDiscovery: domain.Bool(false),
})
fields := details.GetFields()
participantFields := fx.CombinedDetails().GetFields()
participantDetails := fx.CombinedDetails()
participantRelationLinks := fx.GetRelationLinks()
for key, _ := range details.Fields {
require.Equal(t, fields[key], participantFields[key])
require.True(t, participantRelationLinks.Has(key))
for key, _ := range details.Iterate() {
require.True(t, details.Get(key).Equal(participantDetails.Get(key)))
require.True(t, participantRelationLinks.Has(key.String()))
}
}
@ -98,18 +95,17 @@ func TestParticipant_ModifyIdentityDetails(t *testing.T) {
// then
require.NoError(t, err)
details := pbtypes.ToStruct(map[string]interface{}{
bundle.RelationKeyName.String(): "name",
bundle.RelationKeyDescription.String(): "description",
bundle.RelationKeyIconImage.String(): "icon",
bundle.RelationKeyGlobalName.String(): "global",
details := domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyName: domain.String("name"),
bundle.RelationKeyDescription: domain.String("description"),
bundle.RelationKeyIconImage: domain.String("icon"),
bundle.RelationKeyGlobalName: domain.String("global"),
})
fields := details.GetFields()
participantFields := fx.CombinedDetails().GetFields()
participantDetails := fx.CombinedDetails()
participantRelationLinks := fx.GetRelationLinks()
for key, _ := range details.Fields {
require.Equal(t, fields[key], participantFields[key])
require.True(t, participantRelationLinks.Has(key))
for key, _ := range details.Iterate() {
require.True(t, details.Get(key).Equal(participantDetails.Get(key)))
require.True(t, participantRelationLinks.Has(key.String()))
}
}
@ -119,9 +115,9 @@ func TestParticipant_Init(t *testing.T) {
sb := smarttest.New("root")
store := newStoreFixture(t)
store.AddObjects(t, []objectstore.TestObject{{
bundle.RelationKeySpaceId: pbtypes.String("spaceId"),
bundle.RelationKeyId: pbtypes.String("root"),
bundle.RelationKeyName: pbtypes.String("test"),
bundle.RelationKeySpaceId: domain.String("spaceId"),
bundle.RelationKeyId: domain.String("root"),
bundle.RelationKeyName: domain.String("test"),
}})
basicComponent := basic.NewBasic(sb, store, nil, nil, nil)
@ -187,10 +183,10 @@ func newStoreFixture(t *testing.T) *spaceindex.StoreFixture {
bundle.RelationKeySpaceId, bundle.RelationKeyParticipantStatus, bundle.RelationKeyIsHiddenDiscovery,
} {
store.AddObjects(t, []objectstore.TestObject{{
bundle.RelationKeySpaceId: pbtypes.String("space1"),
bundle.RelationKeyUniqueKey: pbtypes.String(rel.URL()),
bundle.RelationKeyId: pbtypes.String(rel.String()),
bundle.RelationKeyRelationKey: pbtypes.String(rel.String()),
bundle.RelationKeySpaceId: domain.String("space1"),
bundle.RelationKeyUniqueKey: domain.String(rel.URL()),
bundle.RelationKeyId: domain.String(rel.String()),
bundle.RelationKeyRelationKey: domain.String(rel.String()),
}})
}

View file

@ -19,7 +19,6 @@ import (
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
type Profile struct {
@ -82,7 +81,7 @@ func (p *Profile) CreationStateMigration(ctx *smartblock.InitContext) migration.
Proc: func(st *state.State) {
template.InitTemplate(st,
template.WithObjectTypesAndLayout([]domain.TypeKey{bundle.TypeKeyProfile}, model.ObjectType_profile),
template.WithDetail(bundle.RelationKeyLayoutAlign, pbtypes.Float64(float64(model.Block_AlignCenter))),
template.WithDetail(bundle.RelationKeyLayoutAlign, domain.Int64(model.Block_AlignCenter)),
migrationSetHidden,
)
},
@ -90,7 +89,7 @@ func (p *Profile) CreationStateMigration(ctx *smartblock.InitContext) migration.
}
func migrationSetHidden(st *state.State) {
st.SetDetail(bundle.RelationKeyIsHidden.String(), pbtypes.Bool(true))
st.SetDetail(bundle.RelationKeyIsHidden, domain.Bool(true))
}
func migrationWithIdentityBlock(st *state.State) {
@ -131,22 +130,16 @@ func (p *Profile) StateMigrations() migration.Migrations {
})
}
func (p *Profile) SetDetails(ctx session.Context, details []*model.Detail, showEvent bool) (err error) {
func (p *Profile) SetDetails(ctx session.Context, details []domain.Detail, showEvent bool) (err error) {
if err = p.AllOperations.SetDetails(ctx, details, showEvent); err != nil {
return
}
p.eventSender.Broadcast(&pb.Event{
Messages: []*pb.EventMessage{
{
Value: &pb.EventMessageValueOfAccountDetails{
AccountDetails: &pb.EventAccountDetails{
ProfileId: p.Id(),
Details: p.Details(),
},
},
},
p.eventSender.Broadcast(event.NewEventSingleMessage(p.SpaceID(), &pb.EventMessageValueOfAccountDetails{
AccountDetails: &pb.EventAccountDetails{
ProfileId: p.Id(),
Details: p.Details().ToProto(),
},
})
}))
return
}

View file

@ -12,7 +12,6 @@ import (
"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/util/pbtypes"
)
const InternalKeyOldProfileData = "oldprofile"
@ -57,10 +56,10 @@ func ExtractCustomState(st *state.State) (userState *state.State, err error) {
}
newState := state.NewDocWithUniqueKey(st.RootId(), blocksMap, uk).(*state.State)
newState.AddRelationLinks(st.GetRelationLinks()...)
newStateDetails := pbtypes.CopyStruct(st.Details(), true)
newName := pbtypes.GetString(newStateDetails, bundle.RelationKeyName.String()) + " [migrated]"
newStateDetails.Fields[bundle.RelationKeyName.String()] = pbtypes.String(newName)
newStateDetails.Fields[bundle.RelationKeyIsHidden.String()] = pbtypes.Bool(false)
newStateDetails := st.Details().Copy()
newName := newStateDetails.GetString(bundle.RelationKeyName) + " [migrated]"
newStateDetails.SetString(bundle.RelationKeyName, newName)
newStateDetails.SetBool(bundle.RelationKeyIsHidden, false)
newState.SetDetails(newStateDetails)
// remove the identity block
newState.Unlink(identityBlockId)
@ -73,7 +72,7 @@ func ExtractCustomState(st *state.State) (userState *state.State, err error) {
return !slices.Contains(whitelistBlocks, s)
})
whitelistDetailKeys := []string{
whitelistDetailKeys := []domain.RelationKey{
"iconEmoji",
"name",
"isHidden",
@ -83,10 +82,10 @@ func ExtractCustomState(st *state.State) (userState *state.State, err error) {
"iconImage",
"iconOption",
}
var keysToRemove []string
for k := range st.Details().GetFields() {
if !slices.Contains(whitelistDetailKeys, k) {
keysToRemove = append(keysToRemove, k)
var keysToRemove []domain.RelationKey
for key, _ := range st.Details().Iterate() {
if !slices.Contains(whitelistDetailKeys, key) {
keysToRemove = append(keysToRemove, key)
}
}
// cleanup custom details from old state

View file

@ -7,9 +7,9 @@ import (
"github.com/stretchr/testify/require"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
var (
@ -889,20 +889,20 @@ func TestProfileMigrationExtractCustomState(t *testing.T) {
"iconImage",
"iconOption",
}
for k, v := range originalStateCopy.Details().GetFields() {
if k == bundle.RelationKeyName.String() {
for k, v := range originalStateCopy.Details().Iterate() {
if k == bundle.RelationKeyName {
// should has suffix in the name
v = pbtypes.String(v.GetStringValue() + " [migrated]")
v = domain.String(v.String() + " [migrated]")
}
if k == bundle.RelationKeyIsHidden.String() {
if k == bundle.RelationKeyIsHidden {
// extracted state should not be hidden
v = pbtypes.Bool(false)
v = domain.Bool(false)
}
require.Truef(t, v.Equal(extractedState.Details().Fields[k]), "detail %s should be equal to original state", k)
require.Truef(t, v.Equal(extractedState.Details().Get(k)), "detail %s should be equal to original state", k)
}
for k, _ := range originalState.Details().GetFields() {
require.Contains(t, whitelistedDetailKeys, k, "old state should not contain %s", k)
for k, _ := range originalState.Details().Iterate() {
require.Contains(t, whitelistedDetailKeys, k.String(), "old state should not contain %s", k)
}
require.Equal(t, bundle.TypeKeyPage, extractedState.ObjectTypeKey())

View file

@ -8,6 +8,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
@ -26,21 +27,21 @@ func TestDependenciesSubscription(t *testing.T) {
fx.objectStore.AddObjects(t, testSpaceId, []objectstore.TestObject{
{
bundle.RelationKeyId: pbtypes.String(space1obj1),
bundle.RelationKeySpaceId: pbtypes.String(testSpaceId),
bundle.RelationKeyName: pbtypes.String("Object 1"),
bundle.RelationKeyId: domain.String(space1obj1),
bundle.RelationKeySpaceId: domain.String(testSpaceId),
bundle.RelationKeyName: domain.String("Object 1"),
},
{
bundle.RelationKeyId: pbtypes.String(space1obj2),
bundle.RelationKeySpaceId: pbtypes.String(testSpaceId),
bundle.RelationKeyName: pbtypes.String("Object 2"),
bundle.RelationKeyId: domain.String(space1obj2),
bundle.RelationKeySpaceId: domain.String(testSpaceId),
bundle.RelationKeyName: domain.String("Object 2"),
},
})
fx.objectStore.AddObjects(t, "space2", []objectstore.TestObject{
{
bundle.RelationKeyId: pbtypes.String(space2obj1),
bundle.RelationKeySpaceId: pbtypes.String("space2"),
bundle.RelationKeyName: pbtypes.String("Object 3"),
bundle.RelationKeyId: domain.String(space2obj1),
bundle.RelationKeySpaceId: domain.String("space2"),
bundle.RelationKeyName: domain.String("Object 3"),
},
})
@ -58,13 +59,11 @@ func TestDependenciesSubscription(t *testing.T) {
)
fx.Doc = state.NewDoc(mainObjId, root.BuildMap()).NewState()
objDetails := &types.Struct{
Fields: map[string]*types.Value{
bundle.RelationKeyId.String(): pbtypes.String(mainObjId),
bundle.RelationKeySpaceId.String(): pbtypes.String(testSpaceId),
bundle.RelationKeyName.String(): pbtypes.String("Main object"),
},
}
objDetails := domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyId: domain.String(mainObjId),
bundle.RelationKeySpaceId: domain.String(testSpaceId),
bundle.RelationKeyName: domain.String("Main object"),
})
fx.Doc.(*state.State).SetDetails(objDetails)
@ -142,21 +141,21 @@ func TestDependenciesSubscription(t *testing.T) {
fx.objectStore.AddObjects(t, testSpaceId, []objectstore.TestObject{
{
bundle.RelationKeyId: pbtypes.String(space1obj1),
bundle.RelationKeySpaceId: pbtypes.String(testSpaceId),
bundle.RelationKeyName: pbtypes.String("Object 1"),
bundle.RelationKeyId: domain.String(space1obj1),
bundle.RelationKeySpaceId: domain.String(testSpaceId),
bundle.RelationKeyName: domain.String("Object 1"),
},
{
bundle.RelationKeyId: pbtypes.String(space1obj2),
bundle.RelationKeySpaceId: pbtypes.String(testSpaceId),
bundle.RelationKeyName: pbtypes.String("Object 2"),
bundle.RelationKeyId: domain.String(space1obj2),
bundle.RelationKeySpaceId: domain.String(testSpaceId),
bundle.RelationKeyName: domain.String("Object 2"),
},
})
fx.objectStore.AddObjects(t, "space2", []objectstore.TestObject{
{
bundle.RelationKeyId: pbtypes.String(space2obj1),
bundle.RelationKeySpaceId: pbtypes.String("space2"),
bundle.RelationKeyName: pbtypes.String("Object 3"),
bundle.RelationKeyId: domain.String(space2obj1),
bundle.RelationKeySpaceId: domain.String("space2"),
bundle.RelationKeyName: domain.String("Object 3"),
},
})

View file

@ -4,11 +4,11 @@ import (
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/object/objectlink"
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/internalflag"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)
@ -18,7 +18,7 @@ func (sb *smartBlock) updateBackLinks(s *state.State) {
log.With("objectID", sb.Id()).Errorf("failed to get inbound links from object store: %s", err)
return
}
s.SetDetailAndBundledRelation(bundle.RelationKeyBacklinks, pbtypes.StringList(backLinks))
s.SetDetailAndBundledRelation(bundle.RelationKeyBacklinks, domain.StringList(backLinks))
}
func (sb *smartBlock) injectLinksDetails(s *state.State) {
@ -35,7 +35,7 @@ func (sb *smartBlock) injectLinksDetails(s *state.State) {
RoundDateIdsToDay: true,
})
links = slice.RemoveMut(links, sb.Id())
s.SetLocalDetail(bundle.RelationKeyLinks.String(), pbtypes.StringList(links))
s.SetLocalDetail(bundle.RelationKeyLinks, domain.StringList(links))
}
func (sb *smartBlock) injectMentions(s *state.State) {
@ -51,7 +51,7 @@ func (sb *smartBlock) injectMentions(s *state.State) {
NoImages: true,
})
mentions = slice.RemoveMut(mentions, sb.Id())
s.SetDetailAndBundledRelation(bundle.RelationKeyMentions, pbtypes.StringList(mentions))
s.SetDetailAndBundledRelation(bundle.RelationKeyMentions, domain.StringList(mentions))
}
func isBacklinksChanged(msgs []simple.EventMessage) bool {

View file

@ -17,7 +17,6 @@ import (
// nolint:misspell
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/any-sync/commonspace/objecttreebuilder"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/editor/template"
@ -120,7 +119,7 @@ func New(
eventSender: eventSender,
objectStore: objectStore,
spaceIdResolver: spaceIdResolver,
lastDepDetails: map[string]*pb.EventObjectDetailsSet{},
lastDepDetails: map[string]*domain.Details{},
}
return s
}
@ -155,9 +154,9 @@ type SmartBlock interface {
History() undo.History
Relations(s *state.State) relationutils.Relations
HasRelation(s *state.State, relationKey string) bool
AddRelationLinks(ctx session.Context, relationIds ...string) (err error)
AddRelationLinksToState(s *state.State, relationIds ...string) (err error)
RemoveExtraRelations(ctx session.Context, relationKeys []string) (err error)
AddRelationLinks(ctx session.Context, relationKeys ...domain.RelationKey) (err error)
AddRelationLinksToState(s *state.State, relationKeys ...domain.RelationKey) (err error)
RemoveExtraRelations(ctx session.Context, relationKeys []domain.RelationKey) (err error)
SetVerticalAlign(ctx session.Context, align model.BlockVerticalAlign, ids ...string) error
SetIsDeleted()
IsDeleted() bool
@ -190,7 +189,7 @@ type DocInfo struct {
Heads []string
Creator string
Type domain.TypeKey
Details *types.Struct
Details *domain.Details
SmartblockType smartblock.SmartBlockType
}
@ -200,7 +199,7 @@ type InitContext struct {
IsNewObject bool
Source source.Source
ObjectTypeKeys []domain.TypeKey
RelationKeys []string
RelationKeys []domain.RelationKey
RequiredInternalRelationKeys []domain.RelationKey // bundled relations that MUST be present in the state
State *state.State
Relations []*model.Relation
@ -235,7 +234,7 @@ type smartBlock struct {
sessions map[string]session.Context
undo undo.History
source source.Source
lastDepDetails map[string]*pb.EventObjectDetailsSet
lastDepDetails map[string]*domain.Details
restrictions restriction.Restrictions
isDeleted bool
disableLayouts bool
@ -314,7 +313,7 @@ func (sb *smartBlock) Type() smartblock.SmartBlockType {
}
func (sb *smartBlock) ObjectTypeID() string {
return pbtypes.GetString(sb.Doc.Details(), bundle.RelationKeyType.String())
return sb.Doc.Details().GetString(bundle.RelationKeyType)
}
func (sb *smartBlock) Init(ctx *InitContext) (err error) {
@ -357,9 +356,9 @@ func (sb *smartBlock) Init(ctx *InitContext) (err error) {
}
// Add bundled relations
var relKeys []domain.RelationKey
for k := range ctx.State.Details().GetFields() {
for k, _ := range ctx.State.Details().Iterate() {
if bundle.HasRelation(k) {
relKeys = append(relKeys, domain.RelationKey(k))
relKeys = append(relKeys, k)
}
}
ctx.State.AddBundledRelationLinks(relKeys...)
@ -379,14 +378,12 @@ func (sb *smartBlock) Init(ctx *InitContext) (err error) {
func (sb *smartBlock) sendObjectCloseEvent(_ ApplyInfo) error {
sb.sendEvent(&pb.Event{
ContextId: sb.Id(),
Messages: []*pb.EventMessage{{
Value: &pb.EventMessageValueOfObjectClose{
Messages: []*pb.EventMessage{
event.NewMessage(sb.SpaceID(), &pb.EventMessageValueOfObjectClose{
ObjectClose: &pb.EventObjectClose{
Id: sb.Id(),
},
},
}},
})
}}),
}})
return nil
}
@ -397,7 +394,11 @@ func (sb *smartBlock) updateRestrictions() {
return
}
sb.restrictions = r
sb.SendEvent([]*pb.EventMessage{{Value: &pb.EventMessageValueOfObjectRestrictionsSet{ObjectRestrictionsSet: &pb.EventObjectRestrictionsSet{Id: sb.Id(), Restrictions: r.Proto()}}}})
sb.SendEvent([]*pb.EventMessage{
event.NewMessage(sb.SpaceID(), &pb.EventMessageValueOfObjectRestrictionsSet{
ObjectRestrictionsSet: &pb.EventObjectRestrictionsSet{Id: sb.Id(), Restrictions: r.Proto()},
}),
})
}
func (sb *smartBlock) SetIsDeleted() {
@ -462,7 +463,7 @@ func (sb *smartBlock) fetchMeta() (details []*model.ObjectViewDetailsSet, err er
perSpace := sb.partitionIdsBySpace(sb.depIds)
recordsCh := make(chan *types.Struct, 10)
recordsCh := make(chan *domain.Details, 10)
sb.recordsSub = database.NewSubscription(nil, recordsCh)
var records []database.Record
@ -496,13 +497,13 @@ func (sb *smartBlock) fetchMeta() (details []*model.ObjectViewDetailsSet, err er
// add self details
details = append(details, &model.ObjectViewDetailsSet{
Id: sb.Id(),
Details: sb.CombinedDetails(),
Details: sb.CombinedDetails().ToProto(),
})
for _, rec := range records {
details = append(details, &model.ObjectViewDetailsSet{
Id: pbtypes.GetString(rec.Details, bundle.RelationKeyId.String()),
Details: rec.Details,
Id: rec.Details.GetString(bundle.RelationKeyId),
Details: rec.Details.ToProto(),
})
}
go sb.metaListener(recordsCh)
@ -545,7 +546,7 @@ func (sb *smartBlock) Unlock() {
sb.Locker.Unlock()
}
func (sb *smartBlock) metaListener(ch chan *types.Struct) {
func (sb *smartBlock) metaListener(ch chan *domain.Details) {
for {
rec, ok := <-ch
if !ok {
@ -557,34 +558,29 @@ func (sb *smartBlock) metaListener(ch chan *types.Struct) {
}
}
func (sb *smartBlock) onMetaChange(details *types.Struct) {
func (sb *smartBlock) onMetaChange(details *domain.Details) {
if details == nil {
return
}
id := pbtypes.GetString(details, bundle.RelationKeyId.String())
msgs := []*pb.EventMessage{}
id := details.GetString(bundle.RelationKeyId)
var msgs []*pb.EventMessage
if v, exists := sb.lastDepDetails[id]; exists {
diff := pbtypes.StructDiff(v.Details, details)
diff := domain.StructDiff(v, details)
if id == sb.Id() {
// if we've got update for ourselves, we are only interested in local-only details, because the rest details changes will be appended when applying records in the current sb
diff = pbtypes.StructFilterKeys(diff, bundle.LocalRelationsKeys)
diff = diff.CopyOnlyKeys(bundle.LocalRelationsKeys...)
}
msgs = append(msgs, state.StructDiffIntoEvents(id, diff)...)
msgs = append(msgs, state.StructDiffIntoEvents(sb.SpaceID(), id, diff)...)
} else {
msgs = append(msgs, &pb.EventMessage{
Value: &pb.EventMessageValueOfObjectDetailsSet{
ObjectDetailsSet: &pb.EventObjectDetailsSet{
Id: id,
Details: details,
},
msgs = append(msgs, event.NewMessage(sb.SpaceID(), &pb.EventMessageValueOfObjectDetailsSet{
ObjectDetailsSet: &pb.EventObjectDetailsSet{
Id: id,
Details: details.ToProto(),
},
})
}
sb.lastDepDetails[id] = &pb.EventObjectDetailsSet{
Id: id,
Details: details,
}))
}
sb.lastDepDetails[id] = details
if len(msgs) == 0 {
return
@ -687,14 +683,14 @@ func (sb *smartBlock) Apply(s *state.State, flags ...ApplyFlag) (err error) {
if s.ParentState() != nil && s.ParentState().IsTheHeaderChange() {
// for the first change allow to set the last modified date from the state
// this used for the object imports
lastModifiedFromState := pbtypes.GetInt64(s.LocalDetails(), bundle.RelationKeyLastModifiedDate.String())
lastModifiedFromState := s.LocalDetails().GetInt64(bundle.RelationKeyLastModifiedDate)
if lastModifiedFromState > 0 {
lastModified = time.Unix(lastModifiedFromState, 0)
}
if existingCreatedDate := pbtypes.GetInt64(s.LocalDetails(), bundle.RelationKeyCreatedDate.String()); existingCreatedDate == 0 || existingCreatedDate > lastModified.Unix() {
if existingCreatedDate := s.LocalDetails().GetInt64(bundle.RelationKeyCreatedDate); existingCreatedDate == 0 || existingCreatedDate > lastModified.Unix() {
// this can happen if we don't have creation date in the root change
s.SetLocalDetail(bundle.RelationKeyCreatedDate.String(), pbtypes.Int64(lastModified.Unix()))
s.SetLocalDetail(bundle.RelationKeyCreatedDate, domain.Int64(lastModified.Unix()))
}
}
@ -709,7 +705,7 @@ func (sb *smartBlock) Apply(s *state.State, flags ...ApplyFlag) (err error) {
migrationVersionUpdated = s.MigrationVersion() != parent.MigrationVersion()
}
msgs, act, err := state.ApplyState(s, !sb.disableLayouts)
msgs, act, err := state.ApplyState(sb.SpaceID(), s, !sb.disableLayouts)
if err != nil {
return
}
@ -739,15 +735,15 @@ func (sb *smartBlock) Apply(s *state.State, flags ...ApplyFlag) (err error) {
}
if !sb.source.ReadOnly() {
// We can set details directly in object's state, they'll be indexed correctly
st.SetLocalDetail(bundle.RelationKeyLastModifiedBy.String(), pbtypes.String(sb.currentParticipantId))
st.SetLocalDetail(bundle.RelationKeyLastModifiedDate.String(), pbtypes.Int64(lastModified.Unix()))
st.SetLocalDetail(bundle.RelationKeyLastModifiedBy, domain.String(sb.currentParticipantId))
st.SetLocalDetail(bundle.RelationKeyLastModifiedDate, domain.Int64(lastModified.Unix()))
}
fileDetailsKeys := st.FileRelationKeys()
var fileDetailsKeysFiltered []string
var fileDetailsKeysFiltered []domain.RelationKey
for _, ch := range changes {
if ds := ch.GetDetailsSet(); ds != nil {
if slice.FindPos(fileDetailsKeys, ds.Key) != -1 {
fileDetailsKeysFiltered = append(fileDetailsKeysFiltered, ds.Key)
if slice.FindPos(fileDetailsKeys, domain.RelationKey(ds.Key)) != -1 {
fileDetailsKeysFiltered = append(fileDetailsKeysFiltered, domain.RelationKey(ds.Key))
}
}
}
@ -908,7 +904,7 @@ func (sb *smartBlock) History() undo.History {
return sb.undo
}
func (sb *smartBlock) AddRelationLinks(ctx session.Context, relationKeys ...string) (err error) {
func (sb *smartBlock) AddRelationLinks(ctx session.Context, relationKeys ...domain.RelationKey) (err error) {
s := sb.NewStateCtx(ctx)
if err = sb.AddRelationLinksToState(s, relationKeys...); err != nil {
return
@ -916,7 +912,7 @@ func (sb *smartBlock) AddRelationLinks(ctx session.Context, relationKeys ...stri
return sb.Apply(s)
}
func (sb *smartBlock) AddRelationLinksToState(s *state.State, relationKeys ...string) (err error) {
func (sb *smartBlock) AddRelationLinksToState(s *state.State, relationKeys ...domain.RelationKey) (err error) {
if len(relationKeys) == 0 {
return
}
@ -946,7 +942,7 @@ func (sb *smartBlock) injectLocalDetails(s *state.State) error {
// so we don't need to traverse changes every time
keys := bundle.LocalAndDerivedRelationKeys
localDetailsFromStore := pbtypes.StructFilterKeys(details, keys)
localDetailsFromStore := details.CopyOnlyKeys(keys...)
s.InjectLocalDetails(localDetailsFromStore)
if p := s.ParentState(); p != nil && !hasPendingLocalDetails {
@ -961,21 +957,21 @@ func (sb *smartBlock) injectLocalDetails(s *state.State) error {
return nil
}
func (sb *smartBlock) getDetailsFromStore() (*types.Struct, error) {
func (sb *smartBlock) getDetailsFromStore() (*domain.Details, error) {
storedDetails, err := sb.spaceIndex.GetDetails(sb.Id())
if err != nil || storedDetails == nil {
return nil, err
}
return pbtypes.CopyStruct(storedDetails.GetDetails(), true), nil
return storedDetails.Copy(), nil
}
func (sb *smartBlock) appendPendingDetails(details *types.Struct) (resultDetails *types.Struct, hasPendingLocalDetails bool) {
func (sb *smartBlock) appendPendingDetails(details *domain.Details) (resultDetails *domain.Details, hasPendingLocalDetails bool) {
// Consume pending details
err := sb.spaceIndex.UpdatePendingLocalDetails(sb.Id(), func(pending *types.Struct) (*types.Struct, error) {
if len(pending.GetFields()) > 0 {
err := sb.spaceIndex.UpdatePendingLocalDetails(sb.Id(), func(pending *domain.Details) (*domain.Details, error) {
if pending.Len() > 0 {
hasPendingLocalDetails = true
}
details = pbtypes.StructMerge(details, pending, false)
details = details.Merge(pending)
return nil, nil
})
if err != nil {
@ -1003,14 +999,14 @@ func (sb *smartBlock) injectCreationInfo(s *state.State) error {
}
if creatorIdentityObjectId != "" {
s.SetDetailAndBundledRelation(bundle.RelationKeyProfileOwnerIdentity, pbtypes.String(creatorIdentityObjectId))
s.SetDetailAndBundledRelation(bundle.RelationKeyProfileOwnerIdentity, domain.String(creatorIdentityObjectId))
}
} else {
// make sure we don't have this relation for other objects
s.RemoveLocalDetail(bundle.RelationKeyProfileOwnerIdentity.String())
s.RemoveLocalDetail(bundle.RelationKeyProfileOwnerIdentity)
}
if pbtypes.GetString(s.LocalDetails(), bundle.RelationKeyCreator.String()) != "" && pbtypes.GetInt64(s.LocalDetails(), bundle.RelationKeyCreatedDate.String()) != 0 {
if s.LocalDetails().GetString(bundle.RelationKeyCreator) != "" && s.LocalDetails().GetInt64(bundle.RelationKeyCreatedDate) != 0 {
return nil
}
@ -1020,24 +1016,24 @@ func (sb *smartBlock) injectCreationInfo(s *state.State) error {
}
if creatorIdentityObjectId != "" {
s.SetDetailAndBundledRelation(bundle.RelationKeyCreator, pbtypes.String(creatorIdentityObjectId))
s.SetDetailAndBundledRelation(bundle.RelationKeyCreator, domain.String(creatorIdentityObjectId))
} else {
// For derived objects we set current identity
s.SetDetailAndBundledRelation(bundle.RelationKeyCreator, pbtypes.String(sb.currentParticipantId))
s.SetDetailAndBundledRelation(bundle.RelationKeyCreator, domain.String(sb.currentParticipantId))
}
if originalCreated := s.OriginalCreatedTimestamp(); originalCreated > 0 {
// means we have imported object, so we need to set original created date
s.SetDetailAndBundledRelation(bundle.RelationKeyCreatedDate, pbtypes.Float64(float64(originalCreated)))
s.SetDetailAndBundledRelation(bundle.RelationKeyCreatedDate, domain.Int64(originalCreated))
// Only set AddedDate once because we have a side effect with treeCreatedDate:
// - When we import object, treeCreateDate is set to time.Now()
// - But after push it is changed to original modified date
// - So after account recovery we will get treeCreateDate = original modified date, which is not equal to AddedDate
if pbtypes.GetInt64(s.Details(), bundle.RelationKeyAddedDate.String()) == 0 {
s.SetDetailAndBundledRelation(bundle.RelationKeyAddedDate, pbtypes.Float64(float64(treeCreatedDate)))
if s.Details().GetInt64(bundle.RelationKeyAddedDate) == 0 {
s.SetDetailAndBundledRelation(bundle.RelationKeyAddedDate, domain.Int64(treeCreatedDate))
}
} else {
s.SetDetailAndBundledRelation(bundle.RelationKeyCreatedDate, pbtypes.Float64(float64(treeCreatedDate)))
s.SetDetailAndBundledRelation(bundle.RelationKeyCreatedDate, domain.Int64(treeCreatedDate))
}
return nil
@ -1053,7 +1049,7 @@ func (sb *smartBlock) SetVerticalAlign(ctx session.Context, align model.BlockVer
return sb.Apply(s)
}
func (sb *smartBlock) RemoveExtraRelations(ctx session.Context, relationIds []string) (err error) {
func (sb *smartBlock) RemoveExtraRelations(ctx session.Context, relationIds []domain.RelationKey) (err error) {
st := sb.NewStateCtx(ctx)
st.RemoveRelation(relationIds...)
@ -1071,7 +1067,7 @@ func (sb *smartBlock) StateAppend(f func(d state.Doc) (s *state.State, changes [
sb.updateRestrictions()
sb.injectDerivedDetails(s, sb.SpaceID(), sb.Type())
sb.execHooks(HookBeforeApply, ApplyInfo{State: s})
msgs, act, err := state.ApplyState(s, !sb.disableLayouts)
msgs, act, err := state.ApplyState(sb.SpaceID(), s, !sb.disableLayouts)
if err != nil {
return err
}
@ -1106,7 +1102,7 @@ func (sb *smartBlock) StateRebuild(d state.Doc) (err error) {
d.(*state.State).SetParent(sb.Doc.(*state.State))
// todo: make store diff
sb.execHooks(HookBeforeApply, ApplyInfo{State: d.(*state.State)})
msgs, _, err := state.ApplyState(d.(*state.State), !sb.disableLayouts)
msgs, _, err := state.ApplyState(sb.SpaceID(), d.(*state.State), !sb.disableLayouts)
log.Infof("changes: stateRebuild: %d events", len(msgs))
if err != nil {
// can't make diff - reopen doc
@ -1181,17 +1177,18 @@ func hasDepIds(relations pbtypes.RelationLinks, act *undo.Action) bool {
if act.Details.Before == nil || act.Details.After == nil {
return true
}
for k, after := range act.Details.After.Fields {
rel := relations.Get(k)
for k, after := range act.Details.After.Iterate() {
rel := relations.Get(string(k))
if rel != nil && (rel.Format == model.RelationFormat_status ||
rel.Format == model.RelationFormat_tag ||
rel.Format == model.RelationFormat_object ||
rel.Format == model.RelationFormat_file ||
isCoverId(rel)) {
before := act.Details.Before.Fields[k]
before := act.Details.Before.Get(k)
// Check that value is actually changed
if before == nil || !before.Equal(after) {
if !before.Ok() || !before.Equal(after) {
return true
}
}
@ -1226,7 +1223,7 @@ func isCoverId(rel *model.RelationLink) bool {
return rel.Key == bundle.RelationKeyCoverId.String()
}
func getChangedFileHashes(s *state.State, fileDetailKeys []string, act undo.Action) (hashes []string) {
func getChangedFileHashes(s *state.State, fileDetailKeys []domain.RelationKey, act undo.Action) (hashes []string) {
for _, nb := range act.Add {
if fh, ok := nb.(simple.FileHashes); ok {
hashes = fh.FillFileHashes(hashes)
@ -1239,11 +1236,11 @@ func getChangedFileHashes(s *state.State, fileDetailKeys []string, act undo.Acti
}
if act.Details != nil {
det := act.Details.After
if det != nil && det.Fields != nil {
for _, field := range fileDetailKeys {
if list := pbtypes.GetStringList(det, field); list != nil {
if det != nil {
for _, detKey := range fileDetailKeys {
if list := det.GetStringList(detKey); len(list) > 0 {
hashes = append(hashes, list...)
} else if s := pbtypes.GetString(det, field); s != "" {
} else if s := det.GetString(detKey); s != "" {
hashes = append(hashes, s)
}
}
@ -1318,10 +1315,10 @@ func (sb *smartBlock) GetDocInfo() DocInfo {
}
func (sb *smartBlock) getDocInfo(st *state.State) DocInfo {
creator := pbtypes.GetString(st.Details(), bundle.RelationKeyCreator.String())
creator := st.Details().GetString(bundle.RelationKeyCreator)
// we don't want any hidden or internal relations here. We want to capture the meaningful outgoing links only
links := pbtypes.GetStringList(sb.LocalDetails(), bundle.RelationKeyLinks.String())
links := sb.LocalDetails().GetStringList(bundle.RelationKeyLinks)
// so links will have this order
// 1. Simple blocks: links, mentions in the text
// 2. Relations(format==Object)
@ -1337,7 +1334,7 @@ func (sb *smartBlock) getDocInfo(st *state.State) DocInfo {
// todo: heads in source and the state may be inconsistent?
heads := sb.source.Heads()
if len(heads) == 0 {
lastChangeId := pbtypes.GetString(st.LocalDetails(), bundle.RelationKeyLastChangeId.String())
lastChangeId := st.LocalDetails().GetString(bundle.RelationKeyLastChangeId)
if lastChangeId != "" {
heads = []string{lastChangeId}
}
@ -1376,17 +1373,17 @@ func removeInternalFlags(s *state.State) {
}
func (sb *smartBlock) setRestrictionsDetail(s *state.State) {
rawRestrictions := make([]int, len(sb.Restrictions().Object))
rawRestrictions := make([]float64, len(sb.Restrictions().Object))
for i, r := range sb.Restrictions().Object {
rawRestrictions[i] = int(r)
rawRestrictions[i] = float64(r)
}
s.SetLocalDetail(bundle.RelationKeyRestrictions.String(), pbtypes.IntList(rawRestrictions...))
s.SetLocalDetail(bundle.RelationKeyRestrictions, domain.Float64List(rawRestrictions))
// todo: verify this logic with clients
if sb.Restrictions().Object.Check(model.Restrictions_Details) != nil &&
sb.Restrictions().Object.Check(model.Restrictions_Blocks) != nil {
s.SetDetailAndBundledRelation(bundle.RelationKeyIsReadonly, pbtypes.Bool(true))
s.SetDetailAndBundledRelation(bundle.RelationKeyIsReadonly, domain.Bool(true))
}
}
@ -1454,15 +1451,16 @@ func SkipFullTextIfHeadsNotChanged(o *IndexOptions) {
// injectDerivedDetails injects the local data
func (sb *smartBlock) injectDerivedDetails(s *state.State, spaceID string, sbt smartblock.SmartBlockType) {
// TODO Pick from source
id := s.RootId()
if id != "" {
s.SetDetailAndBundledRelation(bundle.RelationKeyId, pbtypes.String(id))
s.SetDetailAndBundledRelation(bundle.RelationKeyId, domain.String(id))
}
if v, ok := s.Details().GetFields()[bundle.RelationKeyFileBackupStatus.String()]; ok {
status := filesyncstatus.Status(v.GetNumberValue())
if v, ok := s.Details().TryInt64(bundle.RelationKeyFileBackupStatus); ok {
status := filesyncstatus.Status(v)
// Clients expect syncstatus constants in this relation
s.SetDetailAndBundledRelation(bundle.RelationKeyFileSyncStatus, pbtypes.Int64(int64(status.ToSyncStatus())))
s.SetDetailAndBundledRelation(bundle.RelationKeyFileSyncStatus, domain.Int64(status.ToSyncStatus()))
}
if info := s.GetFileInfo(); info.FileId != "" {
@ -1476,9 +1474,9 @@ func (sb *smartBlock) injectDerivedDetails(s *state.State, spaceID string, sbt s
}
if spaceID != "" {
s.SetDetailAndBundledRelation(bundle.RelationKeySpaceId, pbtypes.String(spaceID))
s.SetDetailAndBundledRelation(bundle.RelationKeySpaceId, domain.String(spaceID))
} else {
log.Errorf("InjectDerivedDetails: failed to set space id for %s: no space id provided, but in details: %s", id, pbtypes.GetString(s.LocalDetails(), bundle.RelationKeySpaceId.String()))
log.Errorf("InjectDerivedDetails: failed to set space id for %s: no space id provided, but in details: %s", id, s.LocalDetails().GetString(bundle.RelationKeySpaceId))
}
if ot := s.ObjectTypeKey(); ot != "" {
typeID, err := sb.space.GetTypeIdByKey(context.Background(), ot)
@ -1486,7 +1484,7 @@ func (sb *smartBlock) injectDerivedDetails(s *state.State, spaceID string, sbt s
log.Errorf("failed to get type id for %s: %v", ot, err)
}
s.SetDetailAndBundledRelation(bundle.RelationKeyType, pbtypes.String(typeID))
s.SetDetailAndBundledRelation(bundle.RelationKeyType, domain.String(typeID))
}
if uki := s.UniqueKeyInternal(); uki != "" {
@ -1501,7 +1499,7 @@ func (sb *smartBlock) injectDerivedDetails(s *state.State, spaceID string, sbt s
if err != nil {
log.Errorf("failed to get unique key for %s: %v", uki, err)
} else {
s.SetDetailAndBundledRelation(bundle.RelationKeyUniqueKey, pbtypes.String(uk.Marshal()))
s.SetDetailAndBundledRelation(bundle.RelationKeyUniqueKey, domain.String(uk.Marshal()))
}
}
@ -1514,16 +1512,16 @@ func (sb *smartBlock) injectDerivedDetails(s *state.State, spaceID string, sbt s
snippet := s.Snippet()
if snippet != "" || s.LocalDetails() != nil {
s.SetDetailAndBundledRelation(bundle.RelationKeySnippet, pbtypes.String(snippet))
s.SetDetailAndBundledRelation(bundle.RelationKeySnippet, domain.String(snippet))
}
// Set isDeleted relation only if isUninstalled is present in details
if isUninstalled := s.Details().GetFields()[bundle.RelationKeyIsUninstalled.String()]; isUninstalled != nil {
if isUninstalled, ok := s.Details().TryBool(bundle.RelationKeyIsUninstalled); ok {
var isDeleted bool
if isUninstalled.GetBoolValue() {
if isUninstalled {
isDeleted = true
}
s.SetDetailAndBundledRelation(bundle.RelationKeyIsDeleted, pbtypes.Bool(isDeleted))
s.SetDetailAndBundledRelation(bundle.RelationKeyIsDeleted, domain.Bool(isDeleted))
}
sb.injectLinksDetails(s)
@ -1532,7 +1530,7 @@ func (sb *smartBlock) injectDerivedDetails(s *state.State, spaceID string, sbt s
}
func (sb *smartBlock) deriveChatId(s *state.State) error {
hasChat := pbtypes.GetBool(s.Details(), bundle.RelationKeyHasChat.String())
hasChat := s.Details().GetBool(bundle.RelationKeyHasChat)
if hasChat {
chatUk, err := domain.NewUniqueKey(smartblock.SmartBlockTypeChatDerivedObject, sb.Id())
if err != nil {
@ -1543,7 +1541,7 @@ func (sb *smartBlock) deriveChatId(s *state.State) error {
if err != nil {
return err
}
s.SetDetailAndBundledRelation(bundle.RelationKeyChatId, pbtypes.String(chatId))
s.SetDetailAndBundledRelation(bundle.RelationKeyChatId, domain.String(chatId))
}
return nil
}

View file

@ -6,7 +6,6 @@ import (
"testing"
"time"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
@ -30,7 +29,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/internalflag"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
func TestSmartBlock_Init(t *testing.T) {
@ -120,7 +118,7 @@ func TestBasic_SetAlign(t *testing.T) {
// then
require.NoError(t, err)
assert.Equal(t, model.Block_AlignRight, st.Get("title").Model().Align)
assert.Equal(t, int64(model.Block_AlignRight), pbtypes.GetInt64(st.Details(), bundle.RelationKeyLayoutAlign.String()))
assert.Equal(t, int64(model.Block_AlignRight), st.Details().GetInt64(bundle.RelationKeyLayoutAlign))
})
}
@ -131,21 +129,13 @@ func TestSmartBlock_getDetailsFromStore(t *testing.T) {
// given
fx := newFixture(id, t)
details := &types.Struct{
Fields: map[string]*types.Value{
"id": pbtypes.String(id),
"number": pbtypes.Float64(2.18281828459045),
"🔥": pbtypes.StringList([]string{"Jeanne d'Arc", "Giordano Bruno", "Capocchio"}),
},
}
err := fx.store.UpdateObjectDetails(context.Background(), id, &types.Struct{
Fields: map[string]*types.Value{
"id": pbtypes.String(id),
"number": pbtypes.Float64(2.18281828459045),
"🔥": pbtypes.StringList([]string{"Jeanne d'Arc", "Giordano Bruno", "Capocchio"}),
},
details := domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
"id": domain.String(id),
"number": domain.Float64(2.18281828459045),
"🔥": domain.StringList([]string{"Jeanne d'Arc", "Giordano Bruno", "Capocchio"}),
})
err := fx.store.UpdateObjectDetails(context.Background(), id, details)
require.NoError(t, err)
// when
@ -185,13 +175,13 @@ func TestSmartBlock_injectBackLinks(t *testing.T) {
require.NoError(t, err)
st := state.NewDoc("", nil).NewState()
st.SetDetailAndBundledRelation(bundle.RelationKeyBacklinks, pbtypes.StringList(backLinks))
st.SetDetailAndBundledRelation(bundle.RelationKeyBacklinks, domain.StringList(backLinks))
// when
fx.updateBackLinks(st)
// then
assert.Equal(t, newBackLinks, pbtypes.GetStringList(st.CombinedDetails(), bundle.RelationKeyBacklinks.String()))
assert.Equal(t, newBackLinks, st.CombinedDetails().GetStringList(bundle.RelationKeyBacklinks))
})
t.Run("back links were found in object store", func(t *testing.T) {
@ -214,8 +204,8 @@ func TestSmartBlock_injectBackLinks(t *testing.T) {
// then
details := st.CombinedDetails()
assert.NotNil(t, pbtypes.GetStringList(details, bundle.RelationKeyBacklinks.String()))
assert.Equal(t, backLinks, pbtypes.GetStringList(details, bundle.RelationKeyBacklinks.String()))
assert.NotNil(t, details.GetStringList(bundle.RelationKeyBacklinks))
assert.Equal(t, backLinks, details.GetStringList(bundle.RelationKeyBacklinks))
})
t.Run("back links were not found in object store", func(t *testing.T) {
@ -228,7 +218,7 @@ func TestSmartBlock_injectBackLinks(t *testing.T) {
fx.updateBackLinks(st)
// then
assert.Len(t, pbtypes.GetStringList(st.CombinedDetails(), bundle.RelationKeyBacklinks.String()), 0)
assert.Len(t, st.CombinedDetails().GetStringList(bundle.RelationKeyBacklinks), 0)
})
}
@ -240,24 +230,24 @@ func TestSmartBlock_updatePendingDetails(t *testing.T) {
fx := newFixture(id, t)
var hasPendingDetails bool
details := &types.Struct{Fields: map[string]*types.Value{}}
details := domain.NewDetails()
// when
_, result := fx.appendPendingDetails(details)
// then
assert.Equal(t, hasPendingDetails, result)
assert.Zero(t, len(details.Fields))
assert.Zero(t, details.Len())
})
t.Run("found pending details", func(t *testing.T) {
// given
fx := newFixture(id, t)
details := &types.Struct{Fields: map[string]*types.Value{}}
details := domain.NewDetails()
err := fx.store.UpdatePendingLocalDetails(id, func(det *types.Struct) (*types.Struct, error) {
det.Fields[bundle.RelationKeyIsDeleted.String()] = pbtypes.Bool(false)
err := fx.store.UpdatePendingLocalDetails(id, func(det *domain.Details) (*domain.Details, error) {
det.Set(bundle.RelationKeyIsDeleted, domain.Bool(false))
return det, nil
})
require.NoError(t, err)
@ -266,12 +256,10 @@ func TestSmartBlock_updatePendingDetails(t *testing.T) {
got, _ := fx.appendPendingDetails(details)
// then
want := &types.Struct{
Fields: map[string]*types.Value{
bundle.RelationKeyId.String(): pbtypes.String(id),
bundle.RelationKeyIsDeleted.String(): pbtypes.Bool(false),
},
}
want := domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyId: domain.String(id),
bundle.RelationKeyIsDeleted: domain.Bool(false),
})
assert.Equal(t, want, got)
})
@ -279,7 +267,7 @@ func TestSmartBlock_updatePendingDetails(t *testing.T) {
// given
fx := newFixture(id, t)
details := &types.Struct{}
details := domain.NewDetails()
// when
_, hasPendingDetails := fx.appendPendingDetails(details)
@ -302,18 +290,18 @@ func TestSmartBlock_injectCreationInfo(t *testing.T) {
}
sb := &smartBlock{source: src}
s := &state.State{}
s.SetLocalDetails(&types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyCreator.String(): pbtypes.String(creator),
bundle.RelationKeyCreatedDate.String(): pbtypes.Int64(creationDate),
}})
s.SetLocalDetails(domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyCreator: domain.String(creator),
bundle.RelationKeyCreatedDate: domain.Int64(creationDate),
}))
// when
err := sb.injectCreationInfo(s)
// then
assert.NoError(t, err)
assert.Equal(t, creator, pbtypes.GetString(s.LocalDetails(), bundle.RelationKeyCreator.String()))
assert.Equal(t, creationDate, pbtypes.GetInt64(s.LocalDetails(), bundle.RelationKeyCreatedDate.String()))
assert.Equal(t, creator, s.LocalDetails().GetString(bundle.RelationKeyCreator))
assert.Equal(t, creationDate, s.LocalDetails().GetInt64(bundle.RelationKeyCreatedDate))
})
t.Run("both creator and creation date are found", func(t *testing.T) {
@ -331,9 +319,9 @@ func TestSmartBlock_injectCreationInfo(t *testing.T) {
// then
assert.NoError(t, err)
assert.Equal(t, creator, pbtypes.GetString(s.LocalDetails(), bundle.RelationKeyCreator.String()))
assert.Equal(t, creator, s.LocalDetails().GetString(bundle.RelationKeyCreator))
assert.NotNil(t, s.GetRelationLinks().Get(bundle.RelationKeyCreator.String()))
assert.Equal(t, creationDate, pbtypes.GetInt64(s.LocalDetails(), bundle.RelationKeyCreatedDate.String()))
assert.Equal(t, creationDate, s.LocalDetails().GetInt64(bundle.RelationKeyCreatedDate))
assert.NotNil(t, s.GetRelationLinks().Get(bundle.RelationKeyCreatedDate.String()))
})
@ -357,13 +345,13 @@ func Test_removeInternalFlags(t *testing.T) {
t.Run("no flags - no changes", func(t *testing.T) {
// given
st := state.NewDoc("test", nil).(*state.State)
st.SetDetail(bundle.RelationKeyInternalFlags.String(), pbtypes.IntList())
st.SetDetail(bundle.RelationKeyInternalFlags, domain.Int64List([]int64{}))
// when
removeInternalFlags(st)
// then
assert.Empty(t, pbtypes.GetIntList(st.CombinedDetails(), bundle.RelationKeyInternalFlags.String()))
assert.Empty(t, st.CombinedDetails().GetInt64List(bundle.RelationKeyInternalFlags))
})
t.Run("EmptyDelete flag is not removed when state is empty", func(t *testing.T) {
// given
@ -375,14 +363,14 @@ func Test_removeInternalFlags(t *testing.T) {
removeInternalFlags(st)
// then
assert.Len(t, pbtypes.GetIntList(st.CombinedDetails(), bundle.RelationKeyInternalFlags.String()), 1)
assert.Len(t, st.CombinedDetails().GetInt64List(bundle.RelationKeyInternalFlags), 1)
})
t.Run("all flags are removed when title is not empty", func(t *testing.T) {
// given
st := state.NewDoc("test", map[string]simple.Block{
"title": simple.New(&model.Block{Id: "title"}),
}).(*state.State)
st.SetDetail(bundle.RelationKeyName.String(), pbtypes.String("some name"))
st.SetDetail(bundle.RelationKeyName, domain.String("some name"))
flags := defaultInternalFlags()
flags.AddToState(st)
@ -390,7 +378,7 @@ func Test_removeInternalFlags(t *testing.T) {
removeInternalFlags(st)
// then
assert.Empty(t, pbtypes.GetIntList(st.CombinedDetails(), bundle.RelationKeyInternalFlags.String()))
assert.Empty(t, st.CombinedDetails().GetInt64List(bundle.RelationKeyInternalFlags))
})
t.Run("all flags are removed when state has non-empty text blocks", func(t *testing.T) {
// given
@ -407,7 +395,7 @@ func Test_removeInternalFlags(t *testing.T) {
removeInternalFlags(st)
// then
assert.Empty(t, pbtypes.GetIntList(st.CombinedDetails(), bundle.RelationKeyInternalFlags.String()))
assert.Empty(t, st.CombinedDetails().GetInt64List(bundle.RelationKeyInternalFlags))
})
}
@ -425,8 +413,8 @@ func TestInjectLocalDetails(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, fx.source.creator, pbtypes.GetString(st.LocalDetails(), bundle.RelationKeyCreator.String()))
assert.Equal(t, fx.source.createdDate, pbtypes.GetInt64(st.LocalDetails(), bundle.RelationKeyCreatedDate.String()))
assert.Equal(t, fx.source.creator, st.LocalDetails().GetString(bundle.RelationKeyCreator))
assert.Equal(t, fx.source.createdDate, st.LocalDetails().GetInt64(bundle.RelationKeyCreatedDate))
})
// TODO More tests
@ -447,13 +435,13 @@ func TestInjectDerivedDetails(t *testing.T) {
"link": simple.New(&model.Block{Id: "link", Content: &model.BlockContentOfLink{Link: &model.BlockContentLink{TargetBlockId: "some_obj"}}}),
}).NewState()
st.AddRelationLinks(&model.RelationLink{Key: bundle.RelationKeyAssignee.String(), Format: model.RelationFormat_object})
st.SetDetail(bundle.RelationKeyAssignee.String(), pbtypes.String("Kirill"))
st.SetDetail(bundle.RelationKeyAssignee, domain.StringList([]string{"Kirill"}))
// when
fx.injectDerivedDetails(st, spaceId, smartblock.SmartBlockTypePage)
// then
assert.Len(t, pbtypes.GetStringList(st.LocalDetails(), bundle.RelationKeyLinks.String()), 3)
assert.Len(t, st.LocalDetails().GetStringList(bundle.RelationKeyLinks), 3)
})
}

View file

@ -9,7 +9,6 @@ import (
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/any-sync/commonspace/objecttreebuilder"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/state"
@ -25,7 +24,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/pkg/lib/threads"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
func New(id string) *SmartTest {
@ -217,17 +215,17 @@ func (st *SmartTest) TemplateCreateFromObjectState() (*state.State, error) {
return st.Doc.NewState().Copy(), nil
}
func (st *SmartTest) AddRelationLinks(ctx session.Context, relationKeys ...string) (err error) {
func (st *SmartTest) AddRelationLinks(ctx session.Context, relationKeys ...domain.RelationKey) (err error) {
for _, key := range relationKeys {
st.Doc.(*state.State).AddRelationLinks(&model.RelationLink{
Key: key,
Key: key.String(),
Format: 0, // todo
})
}
return nil
}
func (st *SmartTest) AddRelationLinksToState(s *state.State, relationKeys ...string) (err error) {
func (st *SmartTest) AddRelationLinksToState(s *state.State, relationKeys ...domain.RelationKey) (err error) {
return st.AddRelationLinks(nil, relationKeys...)
}
@ -239,7 +237,7 @@ func (st *SmartTest) RefreshLocalDetails(ctx session.Context) error {
return nil
}
func (st *SmartTest) RemoveExtraRelations(ctx session.Context, relationKeys []string) (err error) {
func (st *SmartTest) RemoveExtraRelations(ctx session.Context, relationKeys []domain.RelationKey) (err error) {
return nil
}
@ -255,26 +253,26 @@ func (st *SmartTest) SendEvent(msgs []*pb.EventMessage) {
return
}
func (st *SmartTest) SetDetails(ctx session.Context, details []*model.Detail, showEvent bool) (err error) {
dets := &types.Struct{Fields: map[string]*types.Value{}}
func (st *SmartTest) SetDetails(ctx session.Context, details []domain.Detail, showEvent bool) (err error) {
dets := domain.NewDetails()
for _, d := range details {
dets.Fields[d.Key] = d.Value
dets.Set(d.Key, d.Value)
}
st.Doc.(*state.State).SetDetails(dets)
return
}
func (st *SmartTest) SetDetailsAndUpdateLastUsed(ctx session.Context, details []*model.Detail, showEvent bool) (err error) {
func (st *SmartTest) SetDetailsAndUpdateLastUsed(ctx session.Context, details []domain.Detail, showEvent bool) (err error) {
for _, detail := range details {
st.Results.LastUsedUpdates = append(st.Results.LastUsedUpdates, detail.Key)
st.Results.LastUsedUpdates = append(st.Results.LastUsedUpdates, string(detail.Key))
}
return st.SetDetails(ctx, details, showEvent)
}
func (st *SmartTest) UpdateDetails(update func(current *types.Struct) (*types.Struct, error)) (err error) {
func (st *SmartTest) UpdateDetails(update func(current *domain.Details) (*domain.Details, error)) (err error) {
details := st.Doc.(*state.State).CombinedDetails()
if details == nil || details.Fields == nil {
details = &types.Struct{Fields: map[string]*types.Value{}}
if details == nil {
details = domain.NewDetails()
}
newDetails, err := update(details)
if err != nil {
@ -284,27 +282,27 @@ func (st *SmartTest) UpdateDetails(update func(current *types.Struct) (*types.St
return nil
}
func (st *SmartTest) UpdateDetailsAndLastUsed(update func(current *types.Struct) (*types.Struct, error)) (err error) {
func (st *SmartTest) UpdateDetailsAndLastUsed(update func(current *domain.Details) (*domain.Details, error)) (err error) {
details := st.Doc.(*state.State).CombinedDetails()
if details == nil || details.Fields == nil {
details = &types.Struct{Fields: map[string]*types.Value{}}
if details == nil {
details = domain.NewDetails()
}
oldDetails := pbtypes.CopyStruct(details, true)
oldDetails := details.Copy()
newDetails, err := update(details)
if err != nil {
return err
}
diff := pbtypes.StructDiff(oldDetails, newDetails)
if diff == nil || diff.Fields == nil {
diff := domain.StructDiff(oldDetails, newDetails)
if diff == nil {
return nil
}
st.Doc.(*state.State).SetDetails(newDetails)
for key := range diff.Fields {
st.Results.LastUsedUpdates = append(st.Results.LastUsedUpdates, key)
for k, _ := range diff.Iterate() {
st.Results.LastUsedUpdates = append(st.Results.LastUsedUpdates, string(k))
}
return nil
}
@ -360,10 +358,10 @@ func (st *SmartTest) Apply(s *state.State, flags ...smartblock.ApplyFlag) (err e
}
if !keepInternalFlags {
s.RemoveDetail(bundle.RelationKeyInternalFlags.String())
s.RemoveDetail(bundle.RelationKeyInternalFlags)
}
msgs, act, err := state.ApplyState(s, true)
msgs, act, err := state.ApplyState(st.SpaceID(), s, true)
if err != nil {
return
}
@ -392,7 +390,7 @@ func (st *SmartTest) History() undo.History {
func (st *SmartTest) StateRebuild(d state.Doc) (err error) {
d.(*state.State).SetParent(st.Doc.(*state.State))
_, _, err = state.ApplyState(d.(*state.State), false)
_, _, err = state.ApplyState(st.SpaceID(), d.(*state.State), false)
return err
}

View file

@ -7,7 +7,6 @@ import (
"github.com/anyproto/lexid"
"github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/types"
"golang.org/x/exp/slices"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
@ -20,7 +19,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/spaceinfo"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
var spaceViewLog = logging.Logger("core.block.editor.spaceview")
@ -46,7 +44,7 @@ var spaceViewRequiredRelations = []domain.RelationKey{
type spaceService interface {
OnViewUpdated(info spaceinfo.SpacePersistentInfo)
OnWorkspaceChanged(spaceId string, details *types.Struct)
OnWorkspaceChanged(spaceId string, details *domain.Details)
PersonalSpaceId() string
}
@ -120,16 +118,16 @@ func (s *SpaceView) initTemplate(st *state.State) {
func (s *SpaceView) GetExistingInviteInfo() (fileCid string, fileKey string) {
details := s.CombinedDetails()
fileCid = pbtypes.GetString(details, bundle.RelationKeySpaceInviteFileCid.String())
fileKey = pbtypes.GetString(details, bundle.RelationKeySpaceInviteFileKey.String())
fileCid = details.GetString(bundle.RelationKeySpaceInviteFileCid)
fileKey = details.GetString(bundle.RelationKeySpaceInviteFileKey)
return
}
func (s *SpaceView) RemoveExistingInviteInfo() (fileCid string, err error) {
details := s.Details()
fileCid = pbtypes.GetString(details, bundle.RelationKeySpaceInviteFileCid.String())
fileCid = details.GetString(bundle.RelationKeySpaceInviteFileCid)
newState := s.NewState()
newState.RemoveDetail(bundle.RelationKeySpaceInviteFileCid.String(), bundle.RelationKeySpaceInviteFileKey.String())
newState.RemoveDetail(bundle.RelationKeySpaceInviteFileCid, bundle.RelationKeySpaceInviteFileKey)
return fileCid, s.Apply(newState)
}
@ -147,26 +145,26 @@ func (s *SpaceView) SetSpaceLocalInfo(info spaceinfo.SpaceLocalInfo) (err error)
func (s *SpaceView) SetOwner(ownerId string, createdDate int64) (err error) {
st := s.NewState()
if createdDate != 0 {
st.SetDetailAndBundledRelation(bundle.RelationKeyCreatedDate, pbtypes.Int64(createdDate))
st.SetDetailAndBundledRelation(bundle.RelationKeyCreatedDate, domain.Int64(createdDate))
}
st.SetDetailAndBundledRelation(bundle.RelationKeyCreator, pbtypes.String(ownerId))
st.SetDetailAndBundledRelation(bundle.RelationKeyCreator, domain.String(ownerId))
return s.Apply(st)
}
func (s *SpaceView) SetAclIsEmpty(isEmpty bool) (err error) {
st := s.NewState()
st.SetDetailAndBundledRelation(bundle.RelationKeyIsAclShared, pbtypes.Bool(!isEmpty))
st.SetDetailAndBundledRelation(bundle.RelationKeyIsAclShared, domain.Bool(!isEmpty))
s.updateAccessType(st)
return s.Apply(st)
}
func (s *SpaceView) updateAccessType(st *state.State) {
accessType := spaceinfo.AccessType(pbtypes.GetInt64(st.LocalDetails(), bundle.RelationKeySpaceAccessType.String()))
accessType := spaceinfo.AccessType(st.LocalDetails().GetInt64(bundle.RelationKeySpaceAccessType))
if accessType == spaceinfo.AccessTypePersonal {
return
}
isShared := pbtypes.GetBool(st.LocalDetails(), bundle.RelationKeyIsAclShared.String())
shareable := spaceinfo.ShareableStatus(pbtypes.GetInt64(st.LocalDetails(), bundle.RelationKeySpaceShareableStatus.String()))
isShared := st.LocalDetails().GetBool(bundle.RelationKeyIsAclShared)
shareable := spaceinfo.ShareableStatus(st.LocalDetails().GetInt64(bundle.RelationKeySpaceShareableStatus))
if isShared || shareable == spaceinfo.ShareableStatusShareable {
stateSetAccessType(st, spaceinfo.AccessTypeShared)
} else {
@ -176,11 +174,11 @@ func (s *SpaceView) updateAccessType(st *state.State) {
func (s *SpaceView) SetAccessType(acc spaceinfo.AccessType) (err error) {
st := s.NewState()
prev := spaceinfo.AccessType(pbtypes.GetInt64(st.LocalDetails(), bundle.RelationKeySpaceAccessType.String()))
prev := spaceinfo.AccessType(st.LocalDetails().GetInt64(bundle.RelationKeySpaceAccessType))
if prev == spaceinfo.AccessTypePersonal {
return nil
}
st.SetDetailAndBundledRelation(bundle.RelationKeySpaceAccessType, pbtypes.Int64(int64(acc)))
st.SetDetailAndBundledRelation(bundle.RelationKeySpaceAccessType, domain.Int64(acc))
return s.Apply(st)
}
@ -192,18 +190,18 @@ func (s *SpaceView) SetSpacePersistentInfo(info spaceinfo.SpacePersistentInfo) (
func (s *SpaceView) SetSharedSpacesLimit(limit int) (err error) {
st := s.NewState()
st.SetDetailAndBundledRelation(bundle.RelationKeySharedSpacesLimit, pbtypes.Int64(int64(limit)))
st.SetDetailAndBundledRelation(bundle.RelationKeySharedSpacesLimit, domain.Int64(limit))
return s.Apply(st)
}
func (s *SpaceView) GetSharedSpacesLimit() (limit int) {
return int(pbtypes.GetInt64(s.CombinedDetails(), bundle.RelationKeySharedSpacesLimit.String()))
return int(s.CombinedDetails().GetInt64(bundle.RelationKeySharedSpacesLimit))
}
func (s *SpaceView) SetInviteFileInfo(fileCid string, fileKey string) (err error) {
st := s.NewState()
st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteFileCid, pbtypes.String(fileCid))
st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteFileKey, pbtypes.String(fileKey))
st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteFileCid, domain.String(fileCid))
st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteFileKey, domain.String(fileKey))
return s.Apply(st)
}
@ -244,61 +242,56 @@ func (s *SpaceView) targetSpaceID() (id string, err error) {
func (s *SpaceView) getSpacePersistentInfo(st *state.State) (info spaceinfo.SpacePersistentInfo) {
details := st.CombinedDetails()
spaceInfo := spaceinfo.NewSpacePersistentInfo(pbtypes.GetString(details, bundle.RelationKeyTargetSpaceId.String()))
spaceInfo.SetAccountStatus(spaceinfo.AccountStatus(pbtypes.GetInt64(details, bundle.RelationKeySpaceAccountStatus.String()))).
SetAclHeadId(pbtypes.GetString(details, bundle.RelationKeyLatestAclHeadId.String()))
spaceInfo := spaceinfo.NewSpacePersistentInfo(details.GetString(bundle.RelationKeyTargetSpaceId))
spaceInfo.SetAccountStatus(spaceinfo.AccountStatus(details.GetInt64(bundle.RelationKeySpaceAccountStatus))).
SetAclHeadId(details.GetString(bundle.RelationKeyLatestAclHeadId))
return spaceInfo
}
var workspaceKeysToCopy = []string{
bundle.RelationKeyName.String(),
bundle.RelationKeyIconImage.String(),
bundle.RelationKeyIconOption.String(),
bundle.RelationKeySpaceDashboardId.String(),
bundle.RelationKeyCreatedDate.String(),
bundle.RelationKeyChatId.String(),
var workspaceKeysToCopy = []domain.RelationKey{
bundle.RelationKeyName,
bundle.RelationKeyIconImage,
bundle.RelationKeyIconOption,
bundle.RelationKeySpaceDashboardId,
bundle.RelationKeyCreatedDate,
bundle.RelationKeyChatId,
}
func (s *SpaceView) GetSpaceDescription() (data spaceinfo.SpaceDescription) {
details := s.CombinedDetails()
data.Name = pbtypes.GetString(details, bundle.RelationKeyName.String())
data.IconImage = pbtypes.GetString(details, bundle.RelationKeyIconImage.String())
data.Name = details.GetString(bundle.RelationKeyName)
data.IconImage = details.GetString(bundle.RelationKeyIconImage)
return
}
func (s *SpaceView) SetSpaceData(details *types.Struct) error {
func (s *SpaceView) SetSpaceData(details *domain.Details) error {
st := s.NewState()
var changed bool
for k, v := range details.Fields {
for k, v := range details.Iterate() {
if slices.Contains(workspaceKeysToCopy, k) {
// Special case for migration to Files as Objects to handle following situation:
// - We have an icon in Workspace that was created in pre-Files as Objects version
// - We migrate it, change old id to new id
// - Now we need to push details to SpaceView. But if we push NEW id, then old clients will not be able to display image
// - So we need to push old id
if k == bundle.RelationKeyIconImage.String() {
fileId, err := s.fileObjectService.GetFileIdFromObject(v.GetStringValue())
if k == bundle.RelationKeyIconImage {
fileId, err := s.fileObjectService.GetFileIdFromObject(v.String())
if err == nil {
switch v.Kind.(type) {
case *types.Value_StringValue:
v = pbtypes.String(fileId.FileId.String())
case *types.Value_ListValue:
v = pbtypes.StringList([]string{fileId.FileId.String()})
}
v = domain.String(fileId.FileId.String())
}
}
if k == bundle.RelationKeyCreatedDate.String() && s.GetLocalInfo().SpaceId != s.spaceService.PersonalSpaceId() {
if k == bundle.RelationKeyCreatedDate && s.GetLocalInfo().SpaceId != s.spaceService.PersonalSpaceId() {
continue
}
changed = true
st.SetDetailAndBundledRelation(domain.RelationKey(k), v)
st.SetDetailAndBundledRelation(k, v)
}
}
if changed {
if st.ParentState().ParentState() == nil {
// in case prev change was the first one
createdDate := pbtypes.GetInt64(details, bundle.RelationKeyCreatedDate.String())
createdDate := details.GetInt64(bundle.RelationKeyCreatedDate)
if createdDate > 0 {
// we use this state field to save the original created date, otherwise we use the one from the underlying objectTree
st.SetOriginalCreatedTimestamp(createdDate)
@ -312,23 +305,23 @@ func (s *SpaceView) SetSpaceData(details *types.Struct) error {
func (s *SpaceView) UpdateLastOpenedDate() error {
st := s.NewState()
st.SetLocalDetail(bundle.RelationKeyLastOpenedDate.String(), pbtypes.Int64(time.Now().Unix()))
st.SetLocalDetail(bundle.RelationKeyLastOpenedDate, domain.Int64(time.Now().Unix()))
return s.Apply(st, smartblock.NoHistory, smartblock.NoEvent, smartblock.SkipIfNoChanges, smartblock.KeepInternalFlags)
}
func (s *SpaceView) SetOrder(prevViewOrderId string) (string, error) {
st := s.NewState()
spaceOrderId := lx.Next(prevViewOrderId)
st.SetDetail(bundle.RelationKeySpaceOrder.String(), pbtypes.String(spaceOrderId))
st.SetDetail(bundle.RelationKeySpaceOrder, domain.String(spaceOrderId))
return spaceOrderId, s.Apply(st)
}
func (s *SpaceView) SetAfterGivenView(viewOrderId string) error {
st := s.NewState()
spaceOrderId := pbtypes.GetString(st.Details(), bundle.RelationKeySpaceOrder.String())
spaceOrderId := st.Details().GetString(bundle.RelationKeySpaceOrder)
if viewOrderId > spaceOrderId {
spaceOrderId = lx.Next(viewOrderId)
st.SetDetail(bundle.RelationKeySpaceOrder.String(), pbtypes.String(spaceOrderId))
st.SetDetail(bundle.RelationKeySpaceOrder, domain.String(spaceOrderId))
return s.Apply(st)
}
return nil
@ -340,10 +333,10 @@ func (s *SpaceView) SetBetweenViews(prevViewOrderId, afterViewOrderId string) er
if err != nil {
return fmt.Errorf("failed to get before lexid, %w", err)
}
st.SetDetail(bundle.RelationKeySpaceOrder.String(), pbtypes.String(before))
st.SetDetail(bundle.RelationKeySpaceOrder, domain.String(before))
return s.Apply(st)
}
func stateSetAccessType(st *state.State, accessType spaceinfo.AccessType) {
st.SetDetailAndBundledRelation(bundle.RelationKeySpaceAccessType, pbtypes.Int64(int64(accessType)))
st.SetDetailAndBundledRelation(bundle.RelationKeySpaceAccessType, domain.Int64(accessType))
}

View file

@ -5,7 +5,6 @@ import (
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree/mock_objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
@ -13,10 +12,10 @@ import (
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock/smarttest"
"github.com/anyproto/anytype-heart/core/block/migration"
"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/space/spaceinfo"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
func TestSpaceView_AccessType(t *testing.T) {
@ -125,8 +124,8 @@ func TestSpaceView_SetOwner(t *testing.T) {
defer fx.finish()
err := fx.SetOwner("ownerId", 125)
require.NoError(t, err)
require.Equal(t, "ownerId", pbtypes.GetString(fx.CombinedDetails(), bundle.RelationKeyCreator.String()))
require.Equal(t, int64(125), pbtypes.GetInt64(fx.CombinedDetails(), bundle.RelationKeyCreatedDate.String()))
require.Equal(t, "ownerId", fx.CombinedDetails().GetString(bundle.RelationKeyCreator))
require.Equal(t, int64(125), fx.CombinedDetails().GetInt64(bundle.RelationKeyCreatedDate))
}
func TestSpaceView_SetAfterGivenView(t *testing.T) {
@ -140,14 +139,14 @@ func TestSpaceView_SetAfterGivenView(t *testing.T) {
// then
require.NoError(t, err)
assert.NotEmpty(t, pbtypes.GetString(fx.Details(), bundle.RelationKeySpaceOrder.String()))
assert.NotEmpty(t, fx.Details().GetString(bundle.RelationKeySpaceOrder))
})
t.Run("set view after given id, order exist", func(t *testing.T) {
// given
fx := newSpaceViewFixture(t)
defer fx.finish()
state := fx.NewState()
state.SetDetail(bundle.RelationKeySpaceOrder.String(), pbtypes.String("spaceViewOrderId"))
state.SetDetail(bundle.RelationKeySpaceOrder, domain.String("spaceViewOrderId"))
err := fx.Apply(state)
require.NoError(t, err)
@ -156,15 +155,15 @@ func TestSpaceView_SetAfterGivenView(t *testing.T) {
// then
require.NoError(t, err)
assert.NotEqual(t, "spaceViewOrderId", pbtypes.GetString(fx.Details(), bundle.RelationKeySpaceOrder.String()))
assert.True(t, pbtypes.GetString(fx.Details(), bundle.RelationKeySpaceOrder.String()) > "viewOrderId")
assert.NotEqual(t, "spaceViewOrderId", fx.Details().GetString(bundle.RelationKeySpaceOrder))
assert.True(t, fx.Details().GetString(bundle.RelationKeySpaceOrder) > "viewOrderId")
})
t.Run("set view after given id, order exist, but already less than given view", func(t *testing.T) {
// given
fx := newSpaceViewFixture(t)
defer fx.finish()
state := fx.NewState()
state.SetDetail(bundle.RelationKeySpaceOrder.String(), pbtypes.String("viewOrderId"))
state.SetDetail(bundle.RelationKeySpaceOrder, domain.String("viewOrderId"))
err := fx.Apply(state)
require.NoError(t, err)
@ -173,8 +172,8 @@ func TestSpaceView_SetAfterGivenView(t *testing.T) {
// then
require.NoError(t, err)
assert.Equal(t, "viewOrderId", pbtypes.GetString(fx.Details(), bundle.RelationKeySpaceOrder.String()))
assert.True(t, pbtypes.GetString(fx.Details(), bundle.RelationKeySpaceOrder.String()) > "spaceViewOrderId")
assert.Equal(t, "viewOrderId", fx.Details().GetString(bundle.RelationKeySpaceOrder))
assert.True(t, fx.Details().GetString(bundle.RelationKeySpaceOrder) > "spaceViewOrderId")
})
}
@ -189,7 +188,7 @@ func TestSpaceView_SetBetweenViews(t *testing.T) {
// then
require.NoError(t, err)
assert.NotEmpty(t, pbtypes.GetString(fx.Details(), bundle.RelationKeySpaceOrder.String()))
assert.NotEmpty(t, fx.Details().GetString(bundle.RelationKeySpaceOrder))
})
t.Run("set view between", func(t *testing.T) {
// given
@ -204,7 +203,7 @@ func TestSpaceView_SetBetweenViews(t *testing.T) {
// then
require.NoError(t, err)
assert.NotEmpty(t, pbtypes.GetString(fx.Details(), bundle.RelationKeySpaceOrder.String()))
assert.NotEmpty(t, fx.Details().GetString(bundle.RelationKeySpaceOrder))
})
t.Run("after id is empty", func(t *testing.T) {
// given
@ -231,9 +230,9 @@ func TestSpaceView_SetOrder(t *testing.T) {
// then
require.NoError(t, err)
assert.NotEmpty(t, pbtypes.GetString(fx.Details(), bundle.RelationKeySpaceOrder.String()))
assert.Equal(t, order, pbtypes.GetString(fx.Details(), bundle.RelationKeySpaceOrder.String()))
assert.True(t, pbtypes.GetString(fx.Details(), bundle.RelationKeySpaceOrder.String()) > prevViewOrderId)
assert.NotEmpty(t, fx.Details().GetString(bundle.RelationKeySpaceOrder))
assert.Equal(t, order, fx.Details().GetString(bundle.RelationKeySpaceOrder))
assert.True(t, fx.Details().GetString(bundle.RelationKeySpaceOrder) > prevViewOrderId)
})
t.Run("set order, previous id not empty", func(t *testing.T) {
// given
@ -246,9 +245,9 @@ func TestSpaceView_SetOrder(t *testing.T) {
// then
require.NoError(t, err)
assert.NotEmpty(t, pbtypes.GetString(fx.Details(), bundle.RelationKeySpaceOrder.String()))
assert.Equal(t, order, pbtypes.GetString(fx.Details(), bundle.RelationKeySpaceOrder.String()))
assert.True(t, pbtypes.GetString(fx.Details(), bundle.RelationKeySpaceOrder.String()) > prevViewOrderId)
assert.NotEmpty(t, fx.Details().GetString(bundle.RelationKeySpaceOrder))
assert.Equal(t, order, fx.Details().GetString(bundle.RelationKeySpaceOrder))
assert.True(t, fx.Details().GetString(bundle.RelationKeySpaceOrder) > prevViewOrderId)
})
}
@ -262,7 +261,7 @@ func (s *spaceServiceStub) PersonalSpaceId() string {
func (s *spaceServiceStub) OnViewUpdated(info spaceinfo.SpacePersistentInfo) {
}
func (s *spaceServiceStub) OnWorkspaceChanged(spaceId string, details *types.Struct) {
func (s *spaceServiceStub) OnWorkspaceChanged(spaceId string, details *domain.Details) {
}
func NewSpaceViewTest(t *testing.T, targetSpaceId string, tree *mock_objecttree.MockObjectTree) (*SpaceView, error) {
@ -314,7 +313,7 @@ func newSpaceViewFixture(t *testing.T) *spaceViewFixture {
}
func (f *spaceViewFixture) getAccessType() spaceinfo.AccessType {
return spaceinfo.AccessType(pbtypes.GetInt64(f.CombinedDetails(), bundle.RelationKeySpaceAccessType.String()))
return spaceinfo.AccessType(f.CombinedDetails().GetInt64(bundle.RelationKeySpaceAccessType))
}
func (f *spaceViewFixture) finish() {

View file

@ -5,8 +5,6 @@ import (
"fmt"
"strings"
"github.com/globalsign/mgo/bson"
"github.com/gogo/protobuf/types"
"github.com/hashicorp/go-multierror"
"github.com/mb0/diff"
"golang.org/x/exp/slices"
@ -16,7 +14,6 @@ import (
"github.com/anyproto/anytype-heart/core/relationutils"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/addr"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
@ -24,13 +21,8 @@ import (
)
type snapshotOptions struct {
changeId string
internalKey string
uniqueKeyMigration *uniqueKeyMigration
}
type uniqueKeyMigration struct {
sbType smartblock.SmartBlockType
changeId string
internalKey string
}
type SnapshotOption func(*snapshotOptions)
@ -48,17 +40,6 @@ func WithInternalKey(internalKey string) func(*snapshotOptions) {
}
}
// WithUniqueKeyMigration tries to extract unique key from id of supported legacy objects.
// For example, legacy object type has id "ot-page", so unique key will be "ot-page".
// The full list of supported objects you can see in documentation near domain.UniqueKey
func WithUniqueKeyMigration(sbType smartblock.SmartBlockType) func(*snapshotOptions) {
return func(o *snapshotOptions) {
o.uniqueKeyMigration = &uniqueKeyMigration{
sbType: sbType,
}
}
}
func NewDocFromSnapshot(rootId string, snapshot *pb.ChangeSnapshot, opts ...SnapshotOption) Doc {
sOpts := snapshotOptions{}
for _, opt := range opts {
@ -81,22 +62,19 @@ func NewDocFromSnapshot(rootId string, snapshot *pb.ChangeSnapshot, opts ...Snap
removedCollectionKeysMap[t] = struct{}{}
}
detailsToSave := pbtypes.StructCutKeys(snapshot.Data.Details, bundle.LocalAndDerivedRelationKeys)
if err := pbtypes.ValidateStruct(detailsToSave); err != nil {
detailsFromSnapshot := pbtypes.StructCutKeys(snapshot.Data.Details, slice.IntoStrings(bundle.LocalAndDerivedRelationKeys))
if err := pbtypes.ValidateStruct(detailsFromSnapshot); err != nil {
log.Errorf("NewDocFromSnapshot details validation error: %v; details normalized", err)
pbtypes.NormalizeStruct(detailsToSave)
pbtypes.NormalizeStruct(detailsFromSnapshot)
}
if sOpts.uniqueKeyMigration != nil {
migrateAddMissingUniqueKey(sOpts.uniqueKeyMigration.sbType, snapshot)
}
details := domain.NewDetailsFromProto(detailsFromSnapshot)
s := &State{
changeId: sOpts.changeId,
rootId: rootId,
blocks: blocks,
details: detailsToSave,
details: details,
relationLinks: snapshot.Data.RelationLinks,
objectTypeKeys: migrateObjectTypeIDsToKeys(snapshot.Data.ObjectTypes),
fileKeys: fileKeys,
@ -126,9 +104,9 @@ func NewDocFromSnapshot(rootId string, snapshot *pb.ChangeSnapshot, opts ...Snap
func (s *State) SetLastModified(ts int64, identityLink string) {
if ts > 0 {
s.SetDetailAndBundledRelation(bundle.RelationKeyLastModifiedDate, pbtypes.Int64(ts))
s.SetDetailAndBundledRelation(bundle.RelationKeyLastModifiedDate, domain.Int64(ts))
}
s.SetDetailAndBundledRelation(bundle.RelationKeyLastModifiedBy, pbtypes.String(identityLink))
s.SetDetailAndBundledRelation(bundle.RelationKeyLastModifiedBy, domain.String(identityLink))
}
func (s *State) SetChangeId(id string) {
@ -263,35 +241,31 @@ func (s *State) applyChange(ch *pb.ChangeContent) (err error) {
func (s *State) changeBlockDetailsSet(set *pb.ChangeDetailsSet) error {
det := s.Details()
if det == nil || det.Fields == nil {
det = &types.Struct{
Fields: make(map[string]*types.Value),
}
if det == nil {
det = domain.NewDetails()
}
// TODO: GO-2062 Need to refactor details shortening, as it could cut string incorrectly
// set.Value = shortenValueToLimit(s.rootId, set.Key, set.Value)
if s.details == nil || s.details.Fields == nil {
s.details = pbtypes.CopyStruct(det, false)
if s.details == nil {
s.details = det.Copy()
}
if set.Value != nil {
s.details.Fields[set.Key] = set.Value
s.details.SetProtoValue(domain.RelationKey(set.Key), set.Value)
} else {
delete(s.details.Fields, set.Key)
s.details.Delete(domain.RelationKey(set.Key))
}
return nil
}
func (s *State) changeBlockDetailsUnset(unset *pb.ChangeDetailsUnset) error {
det := s.Details()
if det == nil || det.Fields == nil {
det = &types.Struct{
Fields: make(map[string]*types.Value),
}
if det == nil {
det = domain.NewDetails()
}
if s.details == nil || s.details.Fields == nil {
s.details = pbtypes.CopyStruct(det, false)
if s.details == nil {
s.details = det.Copy()
}
delete(s.details.Fields, unset.Key)
s.details.Delete(domain.RelationKey(unset.Key))
return nil
}
@ -307,7 +281,7 @@ func (s *State) changeRelationAdd(add *pb.ChangeRelationAdd) error {
}
func (s *State) changeRelationRemove(rem *pb.ChangeRelationRemove) error {
s.RemoveRelation(rem.RelationKey...)
s.RemoveRelation(slice.StringsInto[domain.RelationKey](rem.RelationKey)...)
return nil
}
func migrateObjectTypeIDToKey(old string) (new string) {
@ -646,7 +620,7 @@ func (s *State) fillChanges(msgs []simple.EventMessage) {
func (s *State) filterLocalAndDerivedRelations(newRelLinks pbtypes.RelationLinks) pbtypes.RelationLinks {
var relLinksWithoutLocal pbtypes.RelationLinks
for _, link := range newRelLinks {
if !slices.Contains(bundle.LocalAndDerivedRelationKeys, link.Key) {
if !slices.Contains(bundle.LocalAndDerivedRelationKeys, domain.RelationKey(link.Key)) {
relLinksWithoutLocal = relLinksWithoutLocal.Append(link)
}
}
@ -656,7 +630,7 @@ func (s *State) filterLocalAndDerivedRelations(newRelLinks pbtypes.RelationLinks
func (s *State) filterLocalAndDerivedRelationsByKey(relationKeys []string) []string {
var relKeysWithoutLocal []string
for _, key := range relationKeys {
if !slices.Contains(bundle.LocalAndDerivedRelationKeys, key) {
if !slices.Contains(bundle.LocalAndDerivedRelationKeys, domain.RelationKey(key)) {
relKeysWithoutLocal = append(relKeysWithoutLocal, key)
}
}
@ -725,36 +699,39 @@ func (s *State) makeStructureChanges(cb *changeBuilder, msg *pb.EventBlockSetChi
}
func (s *State) makeDetailsChanges() (ch []*pb.ChangeContent) {
if s.details == nil || s.details.Fields == nil {
if s.details == nil {
return nil
}
var prev *types.Struct
var prev *domain.Details
if s.parent != nil {
prev = s.parent.Details()
}
if prev == nil || prev.Fields == nil {
prev = &types.Struct{Fields: make(map[string]*types.Value)}
if prev == nil {
prev = domain.NewDetails()
}
curDetails := s.Details()
for k, v := range curDetails.Fields {
pv, ok := prev.Fields[k]
if !ok || !pv.Equal(v) {
for k, v := range curDetails.Iterate() {
prevValue := prev.Get(k)
if !prevValue.Ok() || !prevValue.Equal(v) {
ch = append(ch, &pb.ChangeContent{
Value: &pb.ChangeContentValueOfDetailsSet{
DetailsSet: &pb.ChangeDetailsSet{Key: k, Value: v},
DetailsSet: &pb.ChangeDetailsSet{Key: string(k), Value: v.ToProto()},
},
})
}
}
for k := range prev.Fields {
if _, ok := curDetails.Fields[k]; !ok {
for k, _ := range prev.Iterate() {
if !curDetails.Has(k) {
ch = append(ch, &pb.ChangeContent{
Value: &pb.ChangeContentValueOfDetailsUnset{
DetailsUnset: &pb.ChangeDetailsUnset{Key: k},
DetailsUnset: &pb.ChangeDetailsUnset{Key: string(k)},
},
})
}
}
return
}
@ -990,24 +967,3 @@ func migrateObjectTypeIDsToKeys(objectTypeIDs []string) []domain.TypeKey {
}
return objectTypeKeys
}
// Adds missing unique key for supported smartblock types
func migrateAddMissingUniqueKey(sbType smartblock.SmartBlockType, snapshot *pb.ChangeSnapshot) {
id := pbtypes.GetString(snapshot.Data.Details, bundle.RelationKeyId.String())
uk, err := domain.UnmarshalUniqueKey(id)
if err != nil {
// Maybe it's a relation option?
if bson.IsObjectIdHex(id) {
uk = domain.MustUniqueKey(smartblock.SmartBlockTypeRelationOption, id)
} else {
// Means that smartblock type is not supported
return
}
}
if uk.SmartblockType() != sbType {
log.Errorf("missingKeyMigration: wrong sbtype %s != %s", uk.SmartblockType(), sbType)
return
}
snapshot.Data.Key = uk.InternalKey()
}

View file

@ -46,7 +46,7 @@ func TestState_ChangesCreate_MoveAdd(t *testing.T) {
require.NoError(t, s.InsertTo("b", model.Block_Inner, "1", "2", "4", "5"))
s.Add(simple.New(&model.Block{Id: "3.1"}))
require.NoError(t, s.InsertTo("2", model.Block_Bottom, "3.1"))
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
require.NoError(t, err)
changes := d.(*State).GetChanges()
require.Len(t, changes, 4)
@ -62,7 +62,7 @@ func TestState_ChangesCreate_Collection_Set(t *testing.T) {
d := NewDoc("root", nil)
s := d.NewState()
s.SetInStore([]string{"coll1", "key1"}, pbtypes.String("1"))
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
require.NoError(t, err)
changes := d.(*State).GetChanges()
require.Len(t, changes, 1)
@ -81,7 +81,7 @@ func TestState_ChangesCreate_Collection_Unset(t *testing.T) {
d.(*State).store = makeStoreWithTwoKeysAndValue("coll1", "key1", "1")
s := d.NewState()
s.RemoveFromStore([]string{"coll1", "key1"})
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
require.NoError(t, err)
changes := d.(*State).GetChanges()
require.Len(t, changes, 1)
@ -197,7 +197,7 @@ func TestState_ChangesCreate_StoreSlice(t *testing.T) {
newState := doc.NewState()
newState.UpdateStoreSlice(key, tc.after)
_, _, err := ApplyState(newState, false)
_, _, err := ApplyState("", newState, false)
require.NoError(t, err)
got := doc.(*State).GetChanges()
@ -232,12 +232,12 @@ func TestState_ChangesCreate_MoveAdd_Wrap(t *testing.T) {
s.Add(simple.New(&model.Block{Id: "div", ChildrenIds: []string{"a", "b"}}))
s.Get("root").Model().ChildrenIds = []string{"div"}
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
require.NoError(t, err)
changes := d.(*State).GetChanges()
s2 := dc.NewState()
require.NoError(t, s2.ApplyChange(changes...))
_, _, err = ApplyState(s2, true)
_, _, err = ApplyState("", s2, true)
require.NoError(t, err)
assert.Equal(t, d.(*State).String(), dc.(*State).String())
}
@ -264,12 +264,12 @@ func TestState_ChangesCreate_MoveAdd_Side(t *testing.T) {
s.Unlink("5")
s.InsertTo("1", model.Block_Left, "4", "5")
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
require.NoError(t, err)
changes := d.(*State).GetChanges()
s2 := dc.NewState()
require.NoError(t, s2.ApplyChange(changes...))
_, _, err = ApplyState(s2, true)
_, _, err = ApplyState("", s2, true)
require.NoError(t, err)
assert.Equal(t, d.(*State).String(), dc.(*State).String())
}
@ -290,7 +290,7 @@ func TestState_ChangesCreate_MoveAdd_Side_NewBlock(t *testing.T) {
assertApplyingChanges := func(t *testing.T, state *State, wantState *State, originalState *State) {
AssertTreesEqual(t, wantState.Blocks(), state.Blocks())
_, _, err := ApplyState(state, true)
_, _, err := ApplyState("", state, true)
require.NoError(t, err)
changes := state.GetChanges()
err = originalState.ApplyChange(changes...)
@ -368,11 +368,12 @@ func TestState_SetParent(t *testing.T) {
ns.SetRootId(st.RootId())
ns.SetParent(st)
_, _, err := ApplyState(ns, false)
_, _, err := ApplyState("", ns, false)
require.NoError(t, err)
st2 := orig.Copy()
require.NoError(t, st2.ApplyChange(st.GetChanges()...))
assert.Equal(t, st.StringDebug(), st2.StringDebug())
}
@ -391,7 +392,7 @@ func TestStateNormalizeMerge(t *testing.T) {
s.InsertTo(fmt.Sprintf("common%d", i-1), model.Block_Bottom, id)
}
}
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
require.NoError(t, err)
t.Run("parallel normalize", func(t *testing.T) {
@ -402,7 +403,7 @@ func TestStateNormalizeMerge(t *testing.T) {
stateA.Add(simple.New(&model.Block{Id: "a1"}))
stateA.Add(simple.New(&model.Block{Id: "a2"}))
stateA.InsertTo("common39", model.Block_Bottom, "a1", "a2")
_, _, err = ApplyState(stateA, true)
_, _, err = ApplyState("", stateA, true)
require.NoError(t, err)
// t.Log(docA.String())
changesA := stateA.GetChanges()
@ -411,18 +412,18 @@ func TestStateNormalizeMerge(t *testing.T) {
stateB := docB.NewState()
stateB.Add(simple.New(&model.Block{Id: "b1"}))
stateB.InsertTo("common39", model.Block_Bottom, "b1")
_, _, err = ApplyState(stateB, true)
_, _, err = ApplyState("", stateB, true)
require.NoError(t, err)
// t.Log(docB.String())
changesB := stateB.GetChanges()
s = d.NewState()
require.NoError(t, s.ApplyChange(changesB...))
_, _, err = ApplyStateFastOne(s)
_, _, err = ApplyStateFastOne("", s)
require.NoError(t, err)
s = d.NewState()
require.NoError(t, s.ApplyChange(changesA...))
_, _, err = ApplyState(s, true)
_, _, err = ApplyState("", s, true)
require.NoError(t, err)
s = d.NewState()
@ -438,7 +439,7 @@ func TestStateNormalizeMerge(t *testing.T) {
s.Add(simple.New(&model.Block{Id: "common40"}))
s.InsertTo("common39", model.Block_Bottom, "common40")
ids = append(ids, "common40")
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
require.NoError(t, err)
aIds := []string{}
@ -450,7 +451,7 @@ func TestStateNormalizeMerge(t *testing.T) {
stateA.Add(simple.New(&model.Block{Id: id}))
}
stateA.InsertTo("common0", model.Block_Top, aIds...)
_, _, err = ApplyState(stateA, true)
_, _, err = ApplyState("", stateA, true)
require.NoError(t, err)
changesA := stateA.GetChanges()
@ -463,17 +464,17 @@ func TestStateNormalizeMerge(t *testing.T) {
stateB.Add(simple.New(&model.Block{Id: id}))
}
stateB.InsertTo("common40", model.Block_Bottom, bIds...)
_, _, err = ApplyState(stateB, true)
_, _, err = ApplyState("", stateB, true)
require.NoError(t, err)
changesB := stateB.GetChanges()
s = d.NewState()
require.NoError(t, s.ApplyChange(changesB...))
_, _, err = ApplyStateFastOne(s)
_, _, err = ApplyStateFastOne("", s)
require.NoError(t, err)
s = d.NewState()
require.NoError(t, s.ApplyChange(changesA...))
_, _, err = ApplyState(s, true)
_, _, err = ApplyState("", s, true)
require.NoError(t, err)
s = d.NewState()
@ -505,12 +506,12 @@ func TestState_ChangeDataviewOrder(t *testing.T) {
s := d.NewState()
s.Get("dv").(dataview.Block).SetViewOrder([]string{"3", "1", "2"})
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
require.NoError(t, err)
changes := d.(*State).GetChanges()
s2 := dc.NewState()
require.NoError(t, s2.ApplyChange(changes...))
_, _, err = ApplyState(s2, true)
_, _, err = ApplyState("", s2, true)
require.NoError(t, err)
assert.Equal(t, d.(*State).Pick("dv").Model().String(), dc.(*State).Pick("dv").Model().String())
}
@ -533,11 +534,11 @@ func TestState_ChangeDataviewUnlink(t *testing.T) {
},
}}))
s.InsertTo("root", model.Block_Inner, "dv")
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
changes := d.(*State).GetChanges()
s = d.NewState()
s.Unlink("dv")
_, _, err = ApplyState(s, true)
_, _, err = ApplyState("", s, true)
require.NoError(t, err)
changes = append(changes, d.(*State).GetChanges()...)
@ -546,7 +547,7 @@ func TestState_ChangeDataviewUnlink(t *testing.T) {
require.Nil(t, s2.Get("dv"))
require.Nil(t, s2.Pick("dv"))
_, _, err = ApplyState(s2, true)
_, _, err = ApplyState("", s2, true)
require.NoError(t, err)
require.Nil(t, dc.(*State).Get("dv"))
require.Nil(t, dc.(*State).Pick("dv"))
@ -570,11 +571,11 @@ func TestState_ChangeDataviewRemoveAdd(t *testing.T) {
},
}}))
s.InsertTo("root", model.Block_Inner, "dv")
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
changes := d.(*State).GetChanges()
s = d.NewState()
s.Unlink("dv")
_, _, err = ApplyState(s, true)
_, _, err = ApplyState("", s, true)
require.NoError(t, err)
changes = append(changes, d.(*State).GetChanges()...)
s = d.NewState()
@ -586,7 +587,7 @@ func TestState_ChangeDataviewRemoveAdd(t *testing.T) {
},
}}))
s.InsertTo("root", model.Block_Inner, "dv")
_, _, err = ApplyState(s, true)
_, _, err = ApplyState("", s, true)
require.NoError(t, err)
changes = append(changes, d.(*State).GetChanges()...)
@ -596,7 +597,7 @@ func TestState_ChangeDataviewRemoveAdd(t *testing.T) {
require.Len(t, s2.Get("dv").Model().GetDataview().Views, 1)
require.Equal(t, "2", s2.Get("dv").Model().GetDataview().Views[0].Id)
_, _, err = ApplyState(s2, true)
_, _, err = ApplyState("", s2, true)
require.NoError(t, err)
require.NotNil(t, dc.(*State).Get("dv"))
require.Len(t, dc.(*State).Get("dv").Model().GetDataview().Views, 1)
@ -623,7 +624,7 @@ func TestState_ChangeDataviewRemoveMove(t *testing.T) {
s := d1.NewState()
require.NoError(t, s.ApplyChange(changes...))
ApplyState(s, true)
ApplyState("", s, true)
require.Nil(t, d1.(*State).blocks["b"])
require.NotContains(t, d1.(*State).Pick("s").Model().ChildrenIds, "b")
require.NotContains(t, d1.(*State).Pick("root").Model().ChildrenIds, "b")
@ -692,7 +693,7 @@ func TestRelationChanges(t *testing.T) {
ac := a.Copy()
b := a.NewState()
b.relationLinks = []*model.RelationLink{{Key: "3"}, {Key: "4"}, {Key: "5"}}
_, _, err := ApplyState(b, false)
_, _, err := ApplyState("", b, false)
require.NoError(t, err)
chs := a.GetChanges()
require.NoError(t, ac.ApplyChange(chs...))
@ -708,7 +709,7 @@ func TestLocalRelationChanges(t *testing.T) {
b.relationLinks = []*model.RelationLink{{Key: bundle.RelationKeySyncStatus.String(), Format: model.RelationFormat_number}}
// when
_, _, err := ApplyState(b, false)
_, _, err := ApplyState("", b, false)
require.NoError(t, err)
chs := a.GetChanges()
@ -723,7 +724,7 @@ func TestLocalRelationChanges(t *testing.T) {
b.relationLinks = []*model.RelationLink{}
// when
_, _, err := ApplyState(b, false)
_, _, err := ApplyState("", b, false)
require.NoError(t, err)
chs := a.GetChanges()
@ -738,7 +739,7 @@ func TestLocalRelationChanges(t *testing.T) {
b.relationLinks = []*model.RelationLink{{Key: bundle.RelationKeySpaceId.String(), Format: model.RelationFormat_longtext}}
// when
_, _, err := ApplyState(b, false)
_, _, err := ApplyState("", b, false)
require.NoError(t, err)
chs := a.GetChanges()
@ -753,7 +754,7 @@ func TestLocalRelationChanges(t *testing.T) {
b.relationLinks = []*model.RelationLink{}
// when
_, _, err := ApplyState(b, false)
_, _, err := ApplyState("", b, false)
require.NoError(t, err)
chs := a.GetChanges()
@ -769,7 +770,7 @@ func TestRootBlockChanges(t *testing.T) {
s.Add(simple.New(&model.Block{Id: "new"}))
require.NoError(t, s.InsertTo("root", model.Block_Inner, "new"))
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
require.NoError(t, err)
changes := s.GetChanges()
@ -825,7 +826,7 @@ func buildStateFromAST(root *Block) *State {
Blocks: root.Build(),
},
}).(*State)
ApplyState(st, true)
ApplyState("", st, true)
return st.NewState()
}
@ -879,7 +880,7 @@ func TestRootDeviceChanges(t *testing.T) {
s := a.NewState()
// when
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
// then
assert.Nil(t, err)
@ -897,7 +898,7 @@ func TestRootDeviceChanges(t *testing.T) {
s.AddDevice(device)
// when
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
// then
assert.Nil(t, err)
@ -916,7 +917,7 @@ func TestRootDeviceChanges(t *testing.T) {
s := a.NewState()
s.SetDeviceName("id", "test1")
// when
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
// then
assert.Nil(t, err)
@ -935,7 +936,7 @@ func TestRootDeviceChanges(t *testing.T) {
s.AddDevice(device)
s.parent = nil
// when
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
// then
assert.Nil(t, err)
@ -980,7 +981,7 @@ func TestTableChanges(t *testing.T) {
},
}}))
msgs, _, err := ApplyState(s, true)
msgs, _, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 1)
@ -988,7 +989,7 @@ func TestTableChanges(t *testing.T) {
rows := s.Get("tableRow1")
require.NotNil(t, rows)
rows.Model().GetTableRow().IsHeader = true
msgs, _, err = ApplyState(s, true)
msgs, _, err = ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 1)

View file

@ -4,8 +4,6 @@ import (
"fmt"
"sort"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/block/simple/base"
"github.com/anyproto/anytype-heart/core/block/simple/bookmark"
@ -17,6 +15,8 @@ import (
"github.com/anyproto/anytype-heart/core/block/simple/table"
"github.com/anyproto/anytype-heart/core/block/simple/text"
"github.com/anyproto/anytype-heart/core/block/simple/widget"
"github.com/anyproto/anytype-heart/core/event"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/slice"
@ -314,13 +314,13 @@ func WrapEventMessages(virtual bool, msgs []*pb.EventMessage) []simple.EventMess
return wmsgs
}
func StructDiffIntoEvents(contextId string, diff *types.Struct) (msgs []*pb.EventMessage) {
return StructDiffIntoEventsWithSubIds(contextId, diff, nil, nil)
func StructDiffIntoEvents(spaceId string, contextId string, diff *domain.Details) (msgs []*pb.EventMessage) {
return StructDiffIntoEventsWithSubIds(spaceId, contextId, diff, nil, nil)
}
// StructDiffIntoEvents converts map into events. nil map value converts to Remove event
func StructDiffIntoEventsWithSubIds(contextId string, diff *types.Struct, keys []string, subIds []string) (msgs []*pb.EventMessage) {
if diff == nil || len(diff.Fields) == 0 {
func StructDiffIntoEventsWithSubIds(spaceId string, contextId string, diff *domain.Details, keys []domain.RelationKey, subIds []string) (msgs []*pb.EventMessage) {
if diff.Len() == 0 {
return nil
}
var (
@ -328,39 +328,37 @@ func StructDiffIntoEventsWithSubIds(contextId string, diff *types.Struct, keys [
details []*pb.EventObjectDetailsAmendKeyValue
)
for k, v := range diff.Fields {
for k, v := range diff.Iterate() {
key := string(k)
if len(keys) > 0 && slice.FindPos(keys, k) == -1 {
continue
}
if v == nil {
removed = append(removed, k)
// TODO This is not correct! Rewrite this code to use separate diff structures
if v.IsNull() {
removed = append(removed, key)
continue
}
details = append(details, &pb.EventObjectDetailsAmendKeyValue{Key: k, Value: v})
}
if len(details) > 0 {
msgs = append(msgs, &pb.EventMessage{
Value: &pb.EventMessageValueOfObjectDetailsAmend{
ObjectDetailsAmend: &pb.EventObjectDetailsAmend{
Id: contextId,
Details: details,
SubIds: subIds,
},
},
})
}
if len(removed) > 0 {
msgs = append(msgs, &pb.EventMessage{
Value: &pb.EventMessageValueOfObjectDetailsUnset{
ObjectDetailsUnset: &pb.EventObjectDetailsUnset{
Id: contextId,
Keys: removed,
SubIds: subIds,
},
},
})
details = append(details, &pb.EventObjectDetailsAmendKeyValue{Key: key, Value: v.ToProto()})
}
if len(details) > 0 {
msgs = append(msgs, event.NewMessage(spaceId, &pb.EventMessageValueOfObjectDetailsAmend{
ObjectDetailsAmend: &pb.EventObjectDetailsAmend{
Id: contextId,
Details: details,
SubIds: subIds,
},
}))
}
if len(removed) > 0 {
msgs = append(msgs, event.NewMessage(spaceId, &pb.EventMessageValueOfObjectDetailsUnset{
ObjectDetailsUnset: &pb.EventObjectDetailsUnset{
Id: contextId,
Keys: removed,
SubIds: subIds,
},
}))
}
return
}

View file

@ -50,7 +50,7 @@ func TestState_Normalize(t *testing.T) {
r := NewDoc("1", nil)
r.(*State).Add(simple.New(&model.Block{Id: "1"}))
s := r.NewState()
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 0)
assert.Empty(t, hist)
@ -63,7 +63,7 @@ func TestState_Normalize(t *testing.T) {
}).(*State)
s := r.NewState()
s.Get("one")
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 1)
assert.Len(t, hist.Change, 1)
@ -97,7 +97,7 @@ func TestState_Normalize(t *testing.T) {
s.Get("tableRows")
s.Get("tableColumns")
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 2) // 1 remove + 1 change
assert.Len(t, hist.Change, 1)
@ -122,7 +122,7 @@ func TestState_Normalize(t *testing.T) {
s := r.NewState()
s.Get("c1")
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 2) // 1 remove + 1 change
assert.Len(t, hist.Change, 1)
@ -146,7 +146,7 @@ func TestState_Normalize(t *testing.T) {
s := r.NewState()
s.Unlink("c2")
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 4) // 1 row change + 1 remove + 2 width reset
assert.Len(t, hist.Remove, 2)
@ -168,7 +168,7 @@ func TestState_Normalize(t *testing.T) {
s := r.NewState()
s.normalizeTree()
ApplyState(s, true)
ApplyState("", s, true)
blocks := r.Blocks()
result := []string{}
divs := []string{}
@ -207,7 +207,7 @@ func TestState_Normalize(t *testing.T) {
r.Add(simple.New(&model.Block{Id: "root", ChildrenIds: rootIds}))
s := r.NewState()
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
require.NoError(t, err)
})
@ -221,7 +221,7 @@ func TestState_Normalize(t *testing.T) {
id := fmt.Sprint(i)
s.Add(simple.New(&model.Block{Id: id}))
s.InsertTo(targetId, targetPos, id)
msgs, _, err := ApplyState(s, true)
msgs, _, err := ApplyState("", s, true)
require.NoError(t, err)
for _, msg := range msgs {
if add := msg.Msg.GetBlockAdd(); add != nil {
@ -262,7 +262,7 @@ func TestState_Normalize(t *testing.T) {
for _, b := range ev.Blocks {
r.Add(simple.New(b))
}
_, _, err = ApplyState(r.NewState(), true)
_, _, err = ApplyState("", r.NewState(), true)
require.NoError(t, err)
// t.Log(r.String())
@ -283,7 +283,7 @@ func TestState_Normalize(t *testing.T) {
r.Add(simple.New(&model.Block{Id: "e"}))
s := r.NewState()
require.NoError(t, s.Normalize(false))
_, _, err := ApplyState(s, false)
_, _, err := ApplyState("", s, false)
require.NoError(t, err)
assert.Equal(t, []string{"a", "b", "c"}, r.Pick("root").Model().ChildrenIds)
assert.Equal(t, []string{"d"}, r.Pick("a").Model().ChildrenIds)
@ -305,7 +305,7 @@ func TestState_Normalize(t *testing.T) {
s := r.NewState()
s.normalizeTree()
ApplyState(s, true)
ApplyState("", s, true)
assert.Equal(t, "header", s.Pick(s.RootId()).Model().ChildrenIds[0])
})
@ -336,7 +336,7 @@ func TestState_Normalize(t *testing.T) {
// when
require.NoError(t, s.Normalize(false))
_, msg, err := ApplyState(s, false)
_, msg, err := ApplyState("", s, false)
// then
require.NoError(t, err)
@ -463,7 +463,7 @@ func BenchmarkNormalize(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
ApplyState(r.NewState(), true)
ApplyState("", r.NewState(), true)
}
}

View file

@ -23,7 +23,7 @@ func TestState_InsertTo(t *testing.T) {
s.Add(simple.New(&model.Block{Id: "second"}))
s.InsertTo("", 0, "first", "second")
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 2)
assert.Len(t, hist.Add, 2)
@ -42,7 +42,7 @@ func TestState_InsertTo(t *testing.T) {
s.Add(simple.New(&model.Block{Id: "second"}))
s.InsertTo("target", model.Block_Bottom, "first", "second")
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 2)
assert.Len(t, hist.Add, 2)
@ -59,7 +59,7 @@ func TestState_InsertTo(t *testing.T) {
s.Add(simple.New(&model.Block{Id: "second"}))
s.InsertTo("target", model.Block_Top, "first", "second")
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 2)
assert.Len(t, hist.Add, 2)
@ -76,7 +76,7 @@ func TestState_InsertTo(t *testing.T) {
s.Add(simple.New(&model.Block{Id: "second"}))
s.InsertTo("target", model.Block_Inner, "first", "second")
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 2)
assert.Len(t, hist.Add, 2)
@ -95,7 +95,7 @@ func TestState_InsertTo(t *testing.T) {
s.Add(simple.New(&model.Block{Id: "second"}))
s.InsertTo("target", model.Block_Replace, "first", "second")
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 3)
assert.Len(t, hist.Remove, 1)
@ -106,7 +106,7 @@ func TestState_InsertTo(t *testing.T) {
s = r.NewState()
require.NoError(t, r.InsertTo("first", model.Block_Replace, "child"))
_, _, err = ApplyState(s, true)
_, _, err = ApplyState("", s, true)
require.NoError(t, err)
assert.Equal(t, []string{"child", "second"}, r.Pick("root").Model().ChildrenIds)
})
@ -123,7 +123,7 @@ func TestState_InsertTo(t *testing.T) {
// when
err := s.InsertTo("target", model.Block_Replace, "link")
_, _, err2 := ApplyState(s, true)
_, _, err2 := ApplyState("", s, true)
// then
assert.NoError(t, err)
@ -142,7 +142,7 @@ func TestState_InsertTo(t *testing.T) {
// when
err := s.InsertTo("target", model.Block_Replace, "link")
_, _, err2 := ApplyState(s, true)
_, _, err2 := ApplyState("", s, true)
// then
assert.NoError(t, err)
@ -174,7 +174,7 @@ func TestState_InsertTo(t *testing.T) {
s.Add(simple.New(&model.Block{Id: "second"}))
s.InsertTo("target", pos, "first", "second")
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.NotEmpty(t, msgs)
assert.Len(t, hist.Remove, 0)
@ -207,7 +207,7 @@ func TestState_InsertTo(t *testing.T) {
s.Add(simple.New(&model.Block{Id: "third"}))
s.InsertTo(c1.Model().Id, model.Block_Left, "third")
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 2)
assert.Len(t, hist.Remove, 0)
@ -220,7 +220,7 @@ func TestState_InsertTo(t *testing.T) {
s.Add(simple.New(&model.Block{Id: "third"}))
s.InsertTo(c2.Model().Id, model.Block_Left, "third")
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 2)
assert.Len(t, hist.Remove, 0)
@ -233,7 +233,7 @@ func TestState_InsertTo(t *testing.T) {
s.Add(simple.New(&model.Block{Id: "third"}))
s.InsertTo(c2.Model().Id, model.Block_Right, "third")
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 2)
assert.Len(t, hist.Remove, 0)
@ -250,7 +250,7 @@ func TestState_InsertTo(t *testing.T) {
s.Add(simple.New(&model.Block{Id: "2", ChildrenIds: []string{"1"}}))
s.Get("root").Model().ChildrenIds = []string{"1"}
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
assert.Error(t, err)
})

View file

@ -7,11 +7,14 @@ import (
"strings"
"time"
"github.com/anyproto/any-store/anyenc"
"github.com/gogo/protobuf/types"
"github.com/ipfs/go-cid"
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/block/undo"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/event"
"github.com/anyproto/anytype-heart/core/session"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
@ -49,9 +52,9 @@ type Doc interface {
NewStateCtx(ctx session.Context) *State
Blocks() []*model.Block
Pick(id string) (b simple.Block)
Details() *types.Struct
CombinedDetails() *types.Struct
LocalDetails() *types.Struct
Details() *domain.Details
CombinedDetails() *domain.Details
LocalDetails() *domain.Details
GetRelationLinks() pbtypes.RelationLinks
@ -113,8 +116,8 @@ type State struct {
changes []*pb.ChangeContent
fileInfo FileInfo
fileKeys []pb.ChangeFileKeys // Deprecated
details *types.Struct
localDetails *types.Struct
details *domain.Details
localDetails *domain.Details
relationLinks pbtypes.RelationLinks
notifications map[string]*model.Notification
deviceStore map[string]*model.DeviceInfo
@ -194,7 +197,7 @@ func (s *State) GroupId() string {
}
func (s *State) SpaceID() string {
return pbtypes.GetString(s.LocalDetails(), bundle.RelationKeySpaceId.String())
return s.LocalDetails().GetString(bundle.RelationKeySpaceId)
}
func (s *State) Add(b simple.Block) (ok bool) {
@ -411,25 +414,25 @@ func (s *State) SearchText() string {
return builder.String()
}
func ApplyState(s *State, withLayouts bool) (msgs []simple.EventMessage, action undo.Action, err error) {
return s.apply(false, false, withLayouts)
func ApplyState(spaceId string, s *State, withLayouts bool) (msgs []simple.EventMessage, action undo.Action, err error) {
return s.apply(spaceId, false, false, withLayouts)
}
func ApplyStateFast(s *State) (msgs []simple.EventMessage, action undo.Action, err error) {
return s.apply(true, false, false)
func ApplyStateFast(spaceId string, s *State) (msgs []simple.EventMessage, action undo.Action, err error) {
return s.apply(spaceId, true, false, false)
}
func ApplyStateFastOne(s *State) (msgs []simple.EventMessage, action undo.Action, err error) {
return s.apply(true, true, false)
func ApplyStateFastOne(spaceId string, s *State) (msgs []simple.EventMessage, action undo.Action, err error) {
return s.apply(spaceId, true, true, false)
}
func (s *State) apply(fast, one, withLayouts bool) (msgs []simple.EventMessage, action undo.Action, err error) {
func (s *State) apply(spaceId string, fast, one, withLayouts bool) (msgs []simple.EventMessage, action undo.Action, err error) {
if s.parent != nil && (s.parent.parent != nil || fast) {
s.intermediateApply()
if one {
return
}
return s.parent.apply(fast, one, withLayouts)
return s.parent.apply("", fast, one, withLayouts)
}
if fast {
return
@ -452,7 +455,7 @@ func (s *State) apply(fast, one, withLayouts bool) (msgs []simple.EventMessage,
// apply snippet
if s.Snippet() != s.parent.Snippet() {
s.SetLocalDetail(bundle.RelationKeySnippet.String(), pbtypes.String(s.Snippet()))
s.SetLocalDetail(bundle.RelationKeySnippet, domain.String(s.Snippet()))
}
}
@ -485,13 +488,13 @@ func (s *State) apply(fast, one, withLayouts bool) (msgs []simple.EventMessage,
}
flushNewBlocks := func() {
if len(newBlocks) > 0 {
msgs = append(msgs, simple.EventMessage{Msg: &pb.EventMessage{
Value: &pb.EventMessageValueOfBlockAdd{
msgs = append(msgs, simple.EventMessage{Msg: event.NewMessage(spaceId,
&pb.EventMessageValueOfBlockAdd{
BlockAdd: &pb.EventBlockAdd{
Blocks: newBlocks,
},
},
}})
}),
})
}
newBlocks = nil
}
@ -515,7 +518,7 @@ func (s *State) apply(fast, one, withLayouts bool) (msgs []simple.EventMessage,
db.DetailsInit(s)
}
}
diff, err := orig.Diff(b)
diff, err := orig.Diff(spaceId, b)
if err != nil {
return nil, undo.Action{}, err
}
@ -551,11 +554,9 @@ func (s *State) apply(fast, one, withLayouts bool) (msgs []simple.EventMessage,
}
}
if len(toRemove) > 0 {
msgs = append(msgs, simple.EventMessage{Msg: &pb.EventMessage{
Value: &pb.EventMessageValueOfBlockDelete{
BlockDelete: &pb.EventBlockDelete{BlockIds: toRemove},
},
}})
msgs = append(msgs, simple.EventMessage{Msg: event.NewMessage(s.SpaceID(), &pb.EventMessageValueOfBlockDelete{
BlockDelete: &pb.EventBlockDelete{BlockIds: toRemove},
})})
}
if s.parent != nil && s.relationLinks != nil {
@ -570,26 +571,24 @@ func (s *State) apply(fast, one, withLayouts bool) (msgs []simple.EventMessage,
if len(removed) > 0 {
msgs = append(msgs, WrapEventMessages(false, []*pb.EventMessage{
{
Value: &pb.EventMessageValueOfObjectRelationsRemove{
ObjectRelationsRemove: &pb.EventObjectRelationsRemove{
Id: s.RootId(),
RelationKeys: removed,
},
event.NewMessage(s.SpaceID(), &pb.EventMessageValueOfObjectRelationsRemove{
ObjectRelationsRemove: &pb.EventObjectRelationsRemove{
Id: s.RootId(),
RelationKeys: removed,
},
},
),
})...)
}
if len(added) > 0 {
msgs = append(msgs, WrapEventMessages(false, []*pb.EventMessage{
{
Value: &pb.EventMessageValueOfObjectRelationsAmend{
ObjectRelationsAmend: &pb.EventObjectRelationsAmend{
Id: s.RootId(),
RelationLinks: added,
},
event.NewMessage(s.SpaceID(), &pb.EventMessageValueOfObjectRelationsAmend{
ObjectRelationsAmend: &pb.EventObjectRelationsAmend{
Id: s.RootId(),
RelationLinks: added,
},
},
),
})...)
}
}
@ -621,9 +620,9 @@ func (s *State) apply(fast, one, withLayouts bool) (msgs []simple.EventMessage,
}
if s.parent != nil && s.details != nil {
prev := s.parent.Details()
if diff := pbtypes.StructDiff(prev, s.details); diff != nil {
action.Details = &undo.Details{Before: pbtypes.CopyStruct(prev, false), After: pbtypes.CopyStruct(s.details, false)}
msgs = append(msgs, WrapEventMessages(false, StructDiffIntoEvents(s.RootId(), diff))...)
if diff := domain.StructDiff(prev, s.details); diff != nil {
action.Details = &undo.Details{Before: prev.Copy(), After: s.details.Copy()}
msgs = append(msgs, WrapEventMessages(false, StructDiffIntoEvents(s.SpaceID(), s.RootId(), diff))...)
s.parent.details = s.details
} else if !s.details.Equal(s.parent.details) {
s.parent.details = s.details
@ -652,8 +651,8 @@ func (s *State) apply(fast, one, withLayouts bool) (msgs []simple.EventMessage,
if s.parent != nil && s.localDetails != nil {
prev := s.parent.LocalDetails()
if diff := pbtypes.StructDiff(prev, s.localDetails); diff != nil {
msgs = append(msgs, WrapEventMessages(true, StructDiffIntoEvents(s.RootId(), diff))...)
if diff := domain.StructDiff(prev, s.localDetails); diff != nil {
msgs = append(msgs, WrapEventMessages(true, StructDiffIntoEvents(spaceId, s.RootId(), diff))...)
s.parent.localDetails = s.localDetails
} else if !s.localDetails.Equal(s.parent.localDetails) {
s.parent.localDetails = s.localDetails
@ -818,13 +817,16 @@ func (s *State) StringDebug() string {
}
fmt.Fprintf(buf, "\nDetails:\n")
pbtypes.SortedRange(s.Details(), func(k string, v *types.Value) {
fmt.Fprintf(buf, "\t%s:\t%v\n", k, pbtypes.Sprint(v))
})
arena := &anyenc.Arena{}
for k, v := range s.Details().IterateSorted() {
raw := string(v.ToAnyEnc(arena).MarshalTo(nil))
fmt.Fprintf(buf, "\t%s:\t%v\n", k, raw)
}
fmt.Fprintf(buf, "\nLocal details:\n")
pbtypes.SortedRange(s.LocalDetails(), func(k string, v *types.Value) {
fmt.Fprintf(buf, "\t%s:\t%v\n", k, pbtypes.Sprint(v))
})
for k, v := range s.LocalDetails().IterateSorted() {
raw := string(v.ToAnyEnc(arena).MarshalTo(nil))
fmt.Fprintf(buf, "\t%s:\t%v\n", k, raw)
}
fmt.Fprintf(buf, "\nBlocks:\n")
s.writeString(buf, 0, s.RootId())
fmt.Fprintf(buf, "\nCollection:\n")
@ -839,17 +841,18 @@ func (s *State) StringDebug() string {
return buf.String()
}
func (s *State) SetDetails(d *types.Struct) *State {
func (s *State) SetDetails(d *domain.Details) *State {
// TODO: GO-2062 Need to refactor details shortening, as it could cut string incorrectly
// if d != nil && d.Fields != nil {
// shortenDetailsToLimit(s.rootId, d.Fields)
// }
local := pbtypes.StructFilterKeys(d, bundle.LocalAndDerivedRelationKeys)
if local != nil && local.GetFields() != nil && len(local.GetFields()) > 0 {
for k, v := range local.Fields {
local := d.CopyOnlyKeys(bundle.LocalAndDerivedRelationKeys...)
if local != nil && local.Len() > 0 {
for k, v := range local.Iterate() {
s.SetLocalDetail(k, v)
}
s.details = pbtypes.StructCutKeys(d, bundle.LocalAndDerivedRelationKeys)
s.details = d.CopyWithoutKeys(bundle.LocalAndDerivedRelationKeys...)
return s
}
s.details = d
@ -857,56 +860,41 @@ func (s *State) SetDetails(d *types.Struct) *State {
}
// SetDetailAndBundledRelation sets the detail value and bundled relation in case it is missing
func (s *State) SetDetailAndBundledRelation(key domain.RelationKey, value *types.Value) {
func (s *State) SetDetailAndBundledRelation(key domain.RelationKey, value domain.Value) {
s.AddBundledRelationLinks(key)
s.SetDetail(key.String(), value)
s.SetDetail(key, value)
return
}
func (s *State) SetLocalDetail(key string, value *types.Value) {
func (s *State) SetLocalDetail(key domain.RelationKey, value domain.Value) {
if s.localDetails == nil && s.parent != nil {
d := s.parent.Details()
if d.GetFields() != nil {
if d != nil {
// optimisation so we don't need to copy the struct if nothing has changed
if prev, exists := d.Fields[key]; exists && prev.Equal(value) {
if prev := d.Get(key); prev.Ok() && prev.Equal(value) {
return
}
}
s.localDetails = pbtypes.CopyStruct(s.parent.LocalDetails(), false)
s.localDetails = s.parent.LocalDetails().Copy()
}
if s.localDetails == nil || s.localDetails.Fields == nil {
s.localDetails = &types.Struct{Fields: map[string]*types.Value{}}
if s.localDetails == nil {
s.localDetails = domain.NewDetails()
}
if value == nil {
delete(s.localDetails.Fields, key)
return
}
if err := pbtypes.ValidateValue(value); err != nil {
log.Errorf("invalid value for pb %s: %v", key, err)
}
s.localDetails.Fields[key] = value
s.localDetails.Set(key, value)
return
}
func (s *State) SetLocalDetails(d *types.Struct) {
for k, v := range d.GetFields() {
if v == nil {
delete(d.Fields, k)
}
}
func (s *State) SetLocalDetails(d *domain.Details) {
s.localDetails = d
}
func (s *State) AddDetails(details *types.Struct) {
for k, v := range details.GetFields() {
func (s *State) AddDetails(details *domain.Details) {
for k, v := range details.Iterate() {
s.SetDetail(k, v)
}
}
func (s *State) SetDetail(key string, value *types.Value) {
func (s *State) SetDetail(key domain.RelationKey, value domain.Value) {
// TODO: GO-2062 Need to refactor details shortening, as it could cut string incorrectly
// value = shortenValueToLimit(s.rootId, key, value)
@ -917,34 +905,24 @@ func (s *State) SetDetail(key string, value *types.Value) {
if s.details == nil && s.parent != nil {
d := s.parent.Details()
if d.GetFields() != nil {
if d != nil {
// optimisation so we don't need to copy the struct if nothing has changed
if prev, exists := d.Fields[key]; exists && prev.Equal(value) {
if prev := d.Get(key); prev.Ok() && prev.Equal(value) {
return
}
s.details = d.Copy()
}
s.details = pbtypes.CopyStruct(d, false)
}
if s.details == nil || s.details.Fields == nil {
s.details = &types.Struct{Fields: map[string]*types.Value{}}
if s.details == nil {
s.details = domain.NewDetails()
}
if value == nil {
delete(s.details.Fields, key)
return
}
if err := pbtypes.ValidateValue(value); err != nil {
log.Errorf("invalid value for pb %s: %v", key, err)
}
s.details.Fields[key] = value
s.details.Set(key, value)
return
}
func (s *State) SetAlign(align model.BlockAlign, ids ...string) (err error) {
if len(ids) == 0 {
s.SetDetail(bundle.RelationKeyLayoutAlign.String(), pbtypes.Int64(int64(align)))
s.SetDetail(bundle.RelationKeyLayoutAlign, domain.Int64(align))
ids = []string{TitleBlockID, DescriptionBlockID, FeaturedRelationsID}
}
for _, id := range ids {
@ -998,19 +976,13 @@ func (s *State) SetObjectTypeKeys(objectTypeKeys []domain.TypeKey) *State {
return s
}
func (s *State) InjectLocalDetails(localDetails *types.Struct) {
for key, v := range localDetails.GetFields() {
if v == nil {
continue
}
if _, isNull := v.Kind.(*types.Value_NullValue); isNull {
continue
}
s.SetDetailAndBundledRelation(domain.RelationKey(key), v)
func (s *State) InjectLocalDetails(localDetails *domain.Details) {
for k, v := range localDetails.Iterate() {
s.SetDetailAndBundledRelation(k, v)
}
}
func (s *State) LocalDetails() *types.Struct {
func (s *State) LocalDetails() *domain.Details {
if s.localDetails == nil && s.parent != nil {
return s.parent.LocalDetails()
}
@ -1018,21 +990,12 @@ func (s *State) LocalDetails() *types.Struct {
return s.localDetails
}
func (s *State) CombinedDetails() *types.Struct {
return pbtypes.StructMerge(s.Details(), s.LocalDetails(), false)
func (s *State) CombinedDetails() *domain.Details {
// TODO Implement combined details struct with two underlying details
return s.Details().Merge(s.LocalDetails())
}
func (s *State) HasCombinedDetailsKey(key string) bool {
if pbtypes.HasField(s.Details(), key) {
return true
}
if pbtypes.HasField(s.LocalDetails(), key) {
return true
}
return false
}
func (s *State) Details() *types.Struct {
func (s *State) Details() *domain.Details {
if s.details == nil && s.parent != nil {
return s.parent.Details()
}
@ -1055,7 +1018,7 @@ func (s *State) ObjectTypeKey() domain.TypeKey {
if len(objTypes) == 0 && !s.noObjectType {
log.Debugf("object %s (%s) has %d object types instead of 1",
s.RootId(),
pbtypes.GetString(s.Details(), bundle.RelationKeyName.String()),
s.Details().GetString(bundle.RelationKeyName),
len(objTypes),
)
}
@ -1091,19 +1054,20 @@ func (s *State) Snippet() string {
return textutil.TruncateEllipsized(builder.String(), snippetMaxSize)
}
func (s *State) FileRelationKeys() []string {
var keys []string
func (s *State) FileRelationKeys() []domain.RelationKey {
var keys []domain.RelationKey
for _, rel := range s.GetRelationLinks() {
// coverId can contain both hash or predefined cover id
if rel.Format == model.RelationFormat_file {
if slice.FindPos(keys, rel.Key) == -1 {
keys = append(keys, rel.Key)
key := domain.RelationKey(rel.Key)
if slice.FindPos(keys, key) == -1 {
keys = append(keys, key)
}
}
if rel.Key == bundle.RelationKeyCoverId.String() {
coverType := pbtypes.GetInt64(s.Details(), bundle.RelationKeyCoverType.String())
if (coverType == 1 || coverType == 4) && slice.FindPos(keys, rel.Key) == -1 {
keys = append(keys, rel.Key)
coverType := s.Details().GetInt64(bundle.RelationKeyCoverType)
if (coverType == 1 || coverType == 4) && slice.FindPos(keys, domain.RelationKey(rel.Key)) == -1 {
keys = append(keys, domain.RelationKey(rel.Key))
}
}
}
@ -1132,11 +1096,20 @@ func (s *State) IterateLinkedFilesInDetails(proc func(id string)) {
// Detail is saved only if at least one id is changed
func (s *State) ModifyLinkedFilesInDetails(modifier func(id string) string) {
details := s.Details()
if details == nil || details.Fields == nil {
if details == nil {
return
}
for _, key := range s.FileRelationKeys() {
if key == bundle.RelationKeyCoverId {
v := details.GetString(bundle.RelationKeyCoverId)
_, err := cid.Decode(v)
if err != nil {
// this is an exception cause coverId can contain not a file hash but color
continue
}
}
s.modifyIdsInDetail(details, key, modifier)
}
}
@ -1145,18 +1118,19 @@ func (s *State) ModifyLinkedFilesInDetails(modifier func(id string) string) {
// Detail is saved only if at least one id is changed
func (s *State) ModifyLinkedObjectsInDetails(modifier func(id string) string) {
details := s.Details()
if details == nil || details.Fields == nil {
if details == nil {
return
}
for _, rel := range s.GetRelationLinks() {
if rel.Format == model.RelationFormat_object {
s.modifyIdsInDetail(details, rel.Key, modifier)
s.modifyIdsInDetail(details, domain.RelationKey(rel.Key), modifier)
}
}
}
func (s *State) modifyIdsInDetail(details *types.Struct, key string, modifier func(id string) string) {
if ids := pbtypes.GetStringList(details, key); len(ids) > 0 {
func (s *State) modifyIdsInDetail(details *domain.Details, key domain.RelationKey, modifier func(id string) string) {
// TODO TryStringList in pbtypes return []string{singleValue} for string values
if ids := details.GetStringList(key); len(ids) > 0 {
var anyChanges bool
for i, oldId := range ids {
if oldId == "" {
@ -1169,11 +1143,11 @@ func (s *State) modifyIdsInDetail(details *types.Struct, key string, modifier fu
}
}
if anyChanges {
switch details.Fields[key].Kind.(type) {
case *types.Value_StringValue:
s.SetDetail(key, pbtypes.String(ids[0]))
case *types.Value_ListValue:
s.SetDetail(key, pbtypes.StringList(ids))
v := details.Get(key)
if _, ok := v.TryString(); ok {
s.SetDetail(key, domain.String(ids[0]))
} else if _, ok := v.TryStringList(); ok {
s.SetDetail(key, domain.StringList(ids))
}
}
}
@ -1211,7 +1185,8 @@ func (s *State) CheckRestrictions() (err error) {
}
if rest.Edit {
if ob := s.parent.Pick(id); ob != nil {
if msgs, _ := ob.Diff(b); len(msgs) > 0 {
// SpaceId is empty because only the fact that there is any diff matters here
if msgs, _ := ob.Diff("", b); len(msgs) > 0 {
return ErrRestricted
}
}
@ -1253,7 +1228,7 @@ func (s *State) Validate() (err error) {
// IsEmpty returns whether state has any blocks beside template blocks(root, header, title, etc)
func (s *State) IsEmpty(checkTitle bool) bool {
if checkTitle && pbtypes.GetString(s.Details(), bundle.RelationKeyName.String()) != "" {
if checkTitle && s.Details().GetString(bundle.RelationKeyName) != "" {
return false
}
var emptyTextFound bool
@ -1267,7 +1242,7 @@ func (s *State) IsEmpty(checkTitle bool) bool {
emptyTextFound = true
}
if pbtypes.GetString(s.Details(), bundle.RelationKeyDescription.String()) != "" {
if s.Details().GetString(bundle.RelationKeyDescription) != "" {
return false
}
@ -1311,8 +1286,8 @@ func (s *State) Copy() *State {
ctx: s.ctx,
blocks: blocks,
rootId: s.rootId,
details: pbtypes.CopyStruct(s.Details(), false),
localDetails: pbtypes.CopyStruct(s.LocalDetails(), false),
details: s.Details().Copy(),
localDetails: s.LocalDetails().Copy(),
relationLinks: s.GetRelationLinks(), // Get methods copy inside
objectTypeKeys: objTypes,
noObjectType: s.noObjectType,
@ -1375,12 +1350,13 @@ func (s *State) IsTheHeaderChange() bool {
return s.changeId == s.rootId || s.changeId == "" && s.parent == nil
}
func (s *State) RemoveDetail(keys ...string) (ok bool) {
det := pbtypes.CopyStruct(s.Details(), false)
if det != nil && det.Fields != nil {
func (s *State) RemoveDetail(keys ...domain.RelationKey) (ok bool) {
// TODO It could be lazily copied only if actual deletion is happened
det := s.Details().Copy()
if det != nil {
for _, key := range keys {
if _, ex := det.Fields[key]; ex {
delete(det.Fields, key)
if det.Has(key) {
det.Delete(key)
ok = true
}
}
@ -1391,12 +1367,13 @@ func (s *State) RemoveDetail(keys ...string) (ok bool) {
return s.RemoveLocalDetail(keys...) || ok
}
func (s *State) RemoveLocalDetail(keys ...string) (ok bool) {
det := pbtypes.CopyStruct(s.LocalDetails(), false)
if det != nil && det.Fields != nil {
func (s *State) RemoveLocalDetail(keys ...domain.RelationKey) (ok bool) {
// TODO It could be lazily copied only if actual deletion is happened
det := s.LocalDetails().Copy()
if det != nil {
for _, key := range keys {
if _, ex := det.Fields[key]; ex {
delete(det.Fields, key)
if det.Has(key) {
det.Delete(key)
ok = true
}
}
@ -1707,9 +1684,9 @@ func (s *State) GetChangedStoreKeys(prefixPath ...string) (paths [][]string) {
}
func (s *State) Layout() (model.ObjectTypeLayout, bool) {
if det := s.Details(); det != nil && det.Fields != nil {
if _, ok := det.Fields[bundle.RelationKeyLayout.String()]; ok {
return model.ObjectTypeLayout(pbtypes.GetInt64(det, bundle.RelationKeyLayout.String())), true
if det := s.Details(); det != nil {
if det.Has(bundle.RelationKeyLayout) {
return model.ObjectTypeLayout(det.GetInt64(bundle.RelationKeyLayout)), true
}
}
return 0, false
@ -1752,11 +1729,11 @@ func (s *State) GetRelationLinks() pbtypes.RelationLinks {
return nil
}
func (s *State) RemoveRelation(keys ...string) {
func (s *State) RemoveRelation(keys ...domain.RelationKey) {
relLinks := s.GetRelationLinks()
relLinksFiltered := make(pbtypes.RelationLinks, 0, len(relLinks))
for _, link := range relLinks {
if slice.FindPos(keys, link.Key) >= 0 {
if slice.FindPos(keys, domain.RelationKey(link.Key)) >= 0 {
continue
}
relLinksFiltered = append(relLinksFiltered, &model.RelationLink{
@ -1768,16 +1745,16 @@ func (s *State) RemoveRelation(keys ...string) {
s.RemoveDetail(keys...)
// remove from the list of featured relations
var foundInFeatured bool
featuredList := pbtypes.GetStringList(s.Details(), bundle.RelationKeyFeaturedRelations.String())
featuredList := s.Details().GetStringList(bundle.RelationKeyFeaturedRelations)
featuredList = slice.Filter(featuredList, func(s string) bool {
if slice.FindPos(keys, s) == -1 {
if slice.FindPos(keys, domain.RelationKey(s)) == -1 {
return true
}
foundInFeatured = true
return false
})
if foundInFeatured {
s.SetDetail(bundle.RelationKeyFeaturedRelations.String(), pbtypes.StringList(featuredList))
s.SetDetail(bundle.RelationKeyFeaturedRelations, domain.StringList(featuredList))
}
s.relationLinks = relLinksFiltered
return

View file

@ -192,7 +192,7 @@ func TestApplyState(t *testing.T) {
s.InsertTo("4", model.Block_Bottom, "5")
s.changeId = "4"
msgs, hist, err := ApplyState(s, true)
msgs, hist, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, hist.Add, 2)
assert.Len(t, hist.Change, 1)
@ -206,11 +206,9 @@ func TestApplyState(t *testing.T) {
})
d.BlocksInit(d.(simple.DetailsService))
s := d.NewState()
s.SetDetails(&types.Struct{
Fields: map[string]*types.Value{
"name": pbtypes.String("new name"),
},
})
s.SetDetails(domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
"name": domain.String("new name"),
}))
s.Add(text.NewDetails(&model.Block{
Id: "title",
Content: &model.BlockContentOfText{
@ -225,7 +223,7 @@ func TestApplyState(t *testing.T) {
Text: "name",
Checked: "done",
}))
_, _, err := ApplyState(s, true)
_, _, err := ApplyState("", s, true)
assert.Equal(t, "new name", s.Pick("title").Model().GetText().Text)
require.NoError(t, err)
})
@ -248,12 +246,10 @@ func TestApplyState(t *testing.T) {
})
d.BlocksInit(d.(simple.DetailsService))
s := d.NewState()
s.SetDetails(&types.Struct{
Fields: map[string]*types.Value{
"name": pbtypes.String("new name"),
},
})
msgs, _, err := ApplyState(s, true)
s.SetDetails(domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
"name": domain.String("new name"),
}))
msgs, _, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 2)
})
@ -274,15 +270,13 @@ func TestApplyState(t *testing.T) {
Checked: "done",
}),
})
d.(*State).SetDetail("done", pbtypes.Bool(true))
d.(*State).SetDetail("done", domain.Bool(true))
d.BlocksInit(d.(simple.DetailsService))
s := d.NewState()
s.SetDetails(&types.Struct{
Fields: map[string]*types.Value{
"done": pbtypes.Bool(false),
},
})
msgs, _, err := ApplyState(s, true)
s.SetDetails(domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
"done": domain.Bool(false),
}))
msgs, _, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 2)
})
@ -303,11 +297,11 @@ func TestApplyState(t *testing.T) {
Checked: "done",
}),
})
d.(*State).SetDetail("done", pbtypes.Bool(true))
d.(*State).SetDetail("done", domain.Bool(true))
d.BlocksInit(d.(simple.DetailsService))
s := d.NewState()
s.Get("2").(text.Block).SetChecked(false)
msgs, _, err := ApplyState(s, true)
msgs, _, err := ApplyState("", s, true)
require.NoError(t, err)
assert.Len(t, msgs, 2)
})
@ -2101,7 +2095,7 @@ func TestState_ApplyChangeIgnoreErrDetailsSet(t *testing.T) {
st.ApplyChangeIgnoreErr(change)
// then
assert.Equal(t, "changed value", st.Details().GetFields()["relationKey"].GetStringValue())
assert.Equal(t, "changed value", st.Details().GetString("relationKey"))
})
t.Run("apply DetailsSet change: update existing relation", func(t *testing.T) {
@ -2117,7 +2111,7 @@ func TestState_ApplyChangeIgnoreErrDetailsSet(t *testing.T) {
st.ApplyChangeIgnoreErr(change)
// then
assert.Equal(t, "value", st.Details().GetFields()["relationKey"].GetStringValue())
assert.Equal(t, "value", st.Details().GetString("relationKey"))
})
t.Run("apply DetailsSet change: set relation value to nil", func(t *testing.T) {
@ -2133,7 +2127,7 @@ func TestState_ApplyChangeIgnoreErrDetailsSet(t *testing.T) {
st.ApplyChangeIgnoreErr(change)
// then
assert.Nil(t, st.Details().GetFields()["relationKey"])
assert.False(t, st.Details().Has("relationKey"))
})
}
@ -2156,12 +2150,12 @@ func TestState_ApplyChangeIgnoreErrDetailsUnset(t *testing.T) {
st.ApplyChangeIgnoreErr(change)
// then
assert.Nil(t, st.Details().GetFields()["relationKey"])
assert.False(t, st.Details().Has("relationKey"))
})
t.Run("apply DetailsUnset change: remove existing relation", func(t *testing.T) {
// given
st.SetDetail("relationKey", pbtypes.String("value"))
st.SetDetail("relationKey", domain.String("value"))
change := &pb.ChangeContent{Value: &pb.ChangeContentValueOfDetailsUnset{
DetailsUnset: &pb.ChangeDetailsUnset{
Key: "relationKey",
@ -2172,7 +2166,7 @@ func TestState_ApplyChangeIgnoreErrDetailsUnset(t *testing.T) {
st.ApplyChangeIgnoreErr(change)
// when
assert.Nil(t, st.Details().GetFields()["relationKey"])
assert.False(t, st.Details().Has("relationKey"))
})
}
@ -2590,7 +2584,7 @@ func TestState_RootId(t *testing.T) {
// detail := pbtypes.StringList([]string{"hello", "world", strings.Repeat("a", detailSizeLimit-9)})
//
// //when
// s.SetDetail(bundle.RelationKeyType.String(), pbtypes.CopyVal(detail))
// s.SetDetail(bundle.RelationKeyType, pbtypes.CopyVal(detail))
//
// //then
// assert.Greater(t, detail.Size(), detailSizeLimit)
@ -2845,7 +2839,7 @@ func TestState_FileRelationKeys(t *testing.T) {
keys := s.FileRelationKeys()
// then
expectedKeys := []string{"fileKey1", "fileKey2"}
expectedKeys := []domain.RelationKey{"fileKey1", "fileKey2"}
assert.ElementsMatch(t, keys, expectedKeys)
})
t.Run("duplicated file relations", func(t *testing.T) {
@ -2861,7 +2855,7 @@ func TestState_FileRelationKeys(t *testing.T) {
keys := s.FileRelationKeys()
// then
expectedKeys := []string{"fileKey1"}
expectedKeys := []domain.RelationKey{"fileKey1"}
assert.ElementsMatch(t, keys, expectedKeys)
})
t.Run("coverId relation", func(t *testing.T) {
@ -2870,17 +2864,16 @@ func TestState_FileRelationKeys(t *testing.T) {
relationLinks: pbtypes.RelationLinks{
{Key: bundle.RelationKeyCoverId.String()},
},
details: &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyCoverType.String(): pbtypes.Int64(1),
},
},
details: domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyCoverType: domain.Int64(1),
}),
}
// when
keys := s.FileRelationKeys()
// then
expectedKeys := []string{bundle.RelationKeyCoverId.String()}
expectedKeys := []domain.RelationKey{bundle.RelationKeyCoverId}
assert.ElementsMatch(t, keys, expectedKeys)
})
t.Run("skip coverId relation", func(t *testing.T) {
@ -2889,10 +2882,9 @@ func TestState_FileRelationKeys(t *testing.T) {
relationLinks: pbtypes.RelationLinks{
{Key: bundle.RelationKeyCoverId.String()},
},
details: &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyCoverType.String(): pbtypes.Int64(2),
},
},
details: domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyCoverType: domain.Int64(2),
}),
}
// when
@ -2907,10 +2899,9 @@ func TestState_FileRelationKeys(t *testing.T) {
relationLinks: pbtypes.RelationLinks{
{Key: bundle.RelationKeyCoverId.String()},
},
details: &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyCoverType.String(): pbtypes.Int64(3),
},
},
details: domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyCoverType: domain.Int64(3),
}),
}
// when
@ -2926,17 +2917,16 @@ func TestState_FileRelationKeys(t *testing.T) {
{Format: model.RelationFormat_file, Key: "fileKey1"},
{Key: bundle.RelationKeyCoverId.String()},
},
details: &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyCoverType.String(): pbtypes.Int64(4),
},
},
details: domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyCoverType: domain.Int64(4),
}),
}
// when
keys := s.FileRelationKeys()
// then
expectedKeys := []string{"fileKey1", bundle.RelationKeyCoverId.String()}
expectedKeys := []domain.RelationKey{"fileKey1", bundle.RelationKeyCoverId}
assert.ElementsMatch(t, keys, expectedKeys, "Expected both file keys and cover ID")
})
t.Run("coverType not in details", func(t *testing.T) {

View file

@ -6,14 +6,13 @@ import (
"strings"
"time"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/editor/template"
"github.com/anyproto/anytype-heart/core/block/simple/link"
"github.com/anyproto/anytype-heart/core/block/simple/text"
"github.com/anyproto/anytype-heart/core/block/undo"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/event"
"github.com/anyproto/anytype-heart/core/session"
"github.com/anyproto/anytype-heart/metrics"
@ -448,7 +447,7 @@ func (t *textImpl) TurnInto(ctx session.Context, style model.BlockContentTextSty
textBlock, ok = b.(text.Block)
if !ok {
if linkBlock, ok := b.(link.Block); ok {
var targetDetails *types.Struct
var targetDetails *domain.Details
if targetId := linkBlock.Model().GetLink().TargetBlockId; targetId != "" {
// nolint:errcheck
result, _ := t.objectStore.QueryByIds([]string{targetId})
@ -480,7 +479,7 @@ func (t *textImpl) isLastTextBlockChanged() (bool, error) {
return true, err
}
oldTextBlock := t.lastSetTextState.PickOrigin(t.lastSetTextId)
messages, err := oldTextBlock.Diff(newTextBlock)
messages, err := oldTextBlock.Diff(t.SpaceID(), newTextBlock)
return len(messages) != 0, err
}

View file

@ -15,13 +15,13 @@ import (
"github.com/anyproto/anytype-heart/core/block/simple/link"
"github.com/anyproto/anytype-heart/core/block/simple/text"
"github.com/anyproto/anytype-heart/core/block/undo"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/event/mock_event"
"github.com/anyproto/anytype-heart/core/session"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
func newTextBlock(id, contentText string, childrenIds ...string) simple.Block {
@ -548,8 +548,8 @@ func TestTextImpl_TurnInto(t *testing.T) {
os.AddObjects(t, []spaceindex.TestObject{
{
bundle.RelationKeyId: pbtypes.String("targetId"),
bundle.RelationKeyName: pbtypes.String("link name"),
bundle.RelationKeyId: domain.String("targetId"),
bundle.RelationKeyName: domain.String("link name"),
},
})
@ -571,7 +571,7 @@ func TestTextImpl_removeInternalFlags(t *testing.T) {
sb := smarttest.New(rootID)
sb.AddBlock(simple.New(&model.Block{Id: rootID, ChildrenIds: []string{blockID}})).
AddBlock(newTextBlock(blockID, text))
_ = sb.SetDetails(nil, []*model.Detail{{Key: bundle.RelationKeyInternalFlags.String(), Value: pbtypes.IntList(0, 1, 2)}}, false)
_ = sb.SetDetails(nil, []domain.Detail{{Key: bundle.RelationKeyInternalFlags, Value: domain.Int64List([]int64{0, 1, 2})}}, false)
tb := NewText(sb, nil, nil)
// when
@ -584,7 +584,7 @@ func TestTextImpl_removeInternalFlags(t *testing.T) {
// then
assert.NoError(t, err)
assert.Len(t, pbtypes.GetIntList(sb.Details(), bundle.RelationKeyInternalFlags.String()), 3)
assert.Len(t, sb.Details().GetInt64List(bundle.RelationKeyInternalFlags), 3)
})
t.Run("text is changed", func(t *testing.T) {
@ -593,7 +593,7 @@ func TestTextImpl_removeInternalFlags(t *testing.T) {
sb := smarttest.New(rootID)
sb.AddBlock(simple.New(&model.Block{Id: rootID, ChildrenIds: []string{blockID}})).
AddBlock(newTextBlock(blockID, text))
_ = sb.SetDetails(nil, []*model.Detail{{Key: bundle.RelationKeyInternalFlags.String(), Value: pbtypes.IntList(0, 1, 2)}}, false)
_ = sb.SetDetails(nil, []domain.Detail{{Key: bundle.RelationKeyInternalFlags, Value: domain.Int64List([]int64{0, 1, 2})}}, false)
tb := NewText(sb, nil, nil)
// when
@ -606,7 +606,7 @@ func TestTextImpl_removeInternalFlags(t *testing.T) {
// then
assert.NoError(t, err)
assert.Empty(t, pbtypes.GetIntList(sb.Details(), bundle.RelationKeyInternalFlags.String()))
assert.Empty(t, sb.Details().GetInt64List(bundle.RelationKeyInternalFlags))
})
t.Run("marks are changed", func(t *testing.T) {
@ -615,7 +615,7 @@ func TestTextImpl_removeInternalFlags(t *testing.T) {
sb := smarttest.New(rootID)
sb.AddBlock(simple.New(&model.Block{Id: rootID, ChildrenIds: []string{blockID}})).
AddBlock(newTextBlock(blockID, text))
_ = sb.SetDetails(nil, []*model.Detail{{Key: bundle.RelationKeyInternalFlags.String(), Value: pbtypes.IntList(0, 1, 2)}}, false)
_ = sb.SetDetails(nil, []domain.Detail{{Key: bundle.RelationKeyInternalFlags, Value: domain.Int64List([]int64{0, 1, 2})}}, false)
tb := NewText(sb, nil, nil)
// when
@ -629,7 +629,7 @@ func TestTextImpl_removeInternalFlags(t *testing.T) {
// then
assert.NoError(t, err)
assert.Empty(t, pbtypes.GetIntList(sb.Details(), bundle.RelationKeyInternalFlags.String()))
assert.Empty(t, sb.Details().GetInt64List(bundle.RelationKeyInternalFlags))
})
t.Run("title is changed", func(t *testing.T) {
@ -638,7 +638,7 @@ func TestTextImpl_removeInternalFlags(t *testing.T) {
sb := smarttest.New(rootID)
sb.AddBlock(simple.New(&model.Block{Id: rootID, ChildrenIds: []string{template.TitleBlockId}})).
AddBlock(newTextBlock(template.TitleBlockId, text))
_ = sb.SetDetails(nil, []*model.Detail{{Key: bundle.RelationKeyInternalFlags.String(), Value: pbtypes.IntList(0, 1, 2)}}, false)
_ = sb.SetDetails(nil, []domain.Detail{{Key: bundle.RelationKeyInternalFlags, Value: domain.Int64List([]int64{0, 1, 2})}}, false)
tb := NewText(sb, nil, nil)
// when
@ -651,7 +651,7 @@ func TestTextImpl_removeInternalFlags(t *testing.T) {
// then
assert.NoError(t, err)
flags := pbtypes.GetIntList(sb.Details(), bundle.RelationKeyInternalFlags.String())
flags := sb.Details().GetInt64List(bundle.RelationKeyInternalFlags)
assert.Len(t, flags, 2)
assert.NotContains(t, flags, model.InternalFlag_editorDeleteEmpty)
})

View file

@ -53,10 +53,10 @@ func (m *subObjectsMigration) migrateSubObjects(st *state.State) {
return
}
if pbtypes.GetBool(info.Details, migratedKey) {
if info.Details.GetBool(migratedKey) {
return
}
uniqueKeyRaw := pbtypes.GetString(info.Details, bundle.RelationKeyUniqueKey.String())
uniqueKeyRaw := info.Details.GetString(bundle.RelationKeyUniqueKey)
id, err := m.migrateSubObject(context.Background(), uniqueKeyRaw, info.Details, info.Type)
if err != nil && !errors.Is(err, treestorage.ErrTreeExists) {
log.With("objectID", id).Errorf("failed to migrate subobject: %v", err)
@ -68,7 +68,7 @@ func (m *subObjectsMigration) migrateSubObjects(st *state.State) {
needToAddRestrictions := false
switch info.Type {
case bundle.TypeKeyRelation:
format := pbtypes.GetInt64(info.Details, bundle.RelationKeyRelationFormat.String())
format := info.Details.GetInt64(bundle.RelationKeyRelationFormat)
if format == int64(model.RelationFormat_tag) || format == int64(model.RelationFormat_status) {
// tags and statuses relations values are become readonly
st.SetInStore(append(path, bundle.RelationKeyRelationReadonlyValue.String()), pbtypes.Bool(true))
@ -95,7 +95,7 @@ func (m *subObjectsMigration) migrateSubObjects(st *state.State) {
if needToAddRestrictions {
// we can't add restrictions as it can lead to removing this field on the old client
// todo: revise this
// st.SetInStore(append(path, bundle.RelationKeyRestrictions.String()), pbtypes.IntList(1, 3, 4))
// st.SetInStore(append(path, bundle.RelationKeyRestrictions.TryString()), pbtypes.TryInt64List(1, 3, 4))
}
migratedSubObjects++
@ -114,7 +114,7 @@ func (m *subObjectsMigration) migrateSubObjects(st *state.State) {
func (m *subObjectsMigration) migrateSubObject(
ctx context.Context,
uniqueKeyRaw string,
details *types.Struct,
details *domain.Details,
typeKey domain.TypeKey,
) (id string, err error) {
uniqueKey, err := domain.UnmarshalUniqueKey(uniqueKeyRaw)
@ -181,8 +181,8 @@ func (m *subObjectsMigration) iterateAllSubObjects(st *state.State, proc func(in
continue
}
details := v.StructValue
details.Fields[bundle.RelationKeyUniqueKey.String()] = pbtypes.String(uk.Marshal())
details := domain.NewDetailsFromProto(v.StructValue)
details.SetString(bundle.RelationKeyUniqueKey, uk.Marshal())
proc(smartblock.DocInfo{
Links: nil,

View file

@ -9,7 +9,6 @@ import (
"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/util/pbtypes"
)
type Template struct {
@ -41,7 +40,7 @@ func (t *Template) CreationStateMigration(ctx *smartblock.InitContext) migration
Version: 1,
Proc: func(s *state.State) {
if t.Type() == coresb.SmartBlockTypeTemplate && (len(t.ObjectTypeKeys()) != 2) {
targetObjectTypeId := pbtypes.GetString(s.Details(), bundle.RelationKeyTargetObjectType.String())
targetObjectTypeId := s.Details().GetString(bundle.RelationKeyTargetObjectType)
if targetObjectTypeId != "" {
uniqueKey, err := t.objectStore.GetUniqueKeyById(targetObjectTypeId)
if err == nil && uniqueKey.SmartblockType() != coresb.SmartBlockTypeObjectType {

View file

@ -98,38 +98,38 @@ var WithObjectTypesAndLayout = func(otypes []domain.TypeKey, layout model.Object
otypes = s.ObjectTypeKeys()
}
if !pbtypes.HasField(s.Details(), bundle.RelationKeyLayout.String()) {
s.SetDetailAndBundledRelation(bundle.RelationKeyLayout, pbtypes.Float64(float64(layout)))
if !s.Details().Has(bundle.RelationKeyLayout) {
s.SetDetailAndBundledRelation(bundle.RelationKeyLayout, domain.Int64(layout))
}
}
}
var WithLayout = func(layout model.ObjectTypeLayout) StateTransformer {
return WithDetail(bundle.RelationKeyLayout, pbtypes.Float64(float64(layout)))
return WithDetail(bundle.RelationKeyLayout, domain.Int64(layout))
}
var WithDetailName = func(name string) StateTransformer {
return WithDetail(bundle.RelationKeyName, pbtypes.String(name))
return WithDetail(bundle.RelationKeyName, domain.String(name))
}
var WithDetail = func(key domain.RelationKey, value *types.Value) StateTransformer {
var WithDetail = func(key domain.RelationKey, value domain.Value) StateTransformer {
return func(s *state.State) {
if s.Details() == nil || s.Details().Fields == nil || s.Details().Fields[key.String()] == nil {
if s.Details() == nil || !s.Details().Has(key) {
s.SetDetailAndBundledRelation(key, value)
}
}
}
var WithForcedDetail = func(key domain.RelationKey, value *types.Value) StateTransformer {
var WithForcedDetail = func(key domain.RelationKey, value domain.Value) StateTransformer {
return func(s *state.State) {
if s.Details() == nil || s.Details().Fields == nil || s.Details().Fields[key.String()] == nil || !s.Details().Fields[key.String()].Equal(value) {
if s.Details() == nil || !s.Details().Has(key) || !s.Details().Get(key).Equal(value) {
s.SetDetailAndBundledRelation(key, value)
}
}
}
var WithDetailIconEmoji = func(iconEmoji string) StateTransformer {
return WithDetail(bundle.RelationKeyIconEmoji, pbtypes.String(iconEmoji))
return WithDetail(bundle.RelationKeyIconEmoji, domain.String(iconEmoji))
}
var RequireHeader = StateTransformer(func(s *state.State) {
@ -172,8 +172,8 @@ var WithTitle = StateTransformer(func(s *state.State) {
var (
align model.BlockAlign
)
if pbtypes.HasField(s.Details(), bundle.RelationKeyLayoutAlign.String()) {
alignN := int32(pbtypes.GetFloat64(s.Details(), bundle.RelationKeyLayoutAlign.String()))
if s.Details().Has(bundle.RelationKeyLayoutAlign) {
alignN := int32(s.Details().GetInt64(bundle.RelationKeyLayoutAlign))
if alignN >= 0 && alignN <= 2 {
align = model.BlockAlign(alignN)
}
@ -222,7 +222,7 @@ var WithTitle = StateTransformer(func(s *state.State) {
// WithDefaultFeaturedRelations **MUST** be called before WithDescription
var WithDefaultFeaturedRelations = func(s *state.State) {
if !pbtypes.HasField(s.Details(), bundle.RelationKeyFeaturedRelations.String()) {
if !s.Details().Has(bundle.RelationKeyFeaturedRelations) {
var fr = []string{bundle.RelationKeyType.String()}
layout, _ := s.Layout()
switch layout {
@ -234,41 +234,43 @@ var WithDefaultFeaturedRelations = func(s *state.State) {
fr = []string{bundle.RelationKeyType.String(), bundle.RelationKeyBacklinks.String()}
case model.ObjectType_file, model.ObjectType_image, model.ObjectType_audio, model.ObjectType_video:
fr = []string{bundle.RelationKeyType.String(), bundle.RelationKeyTag.String(), bundle.RelationKeyBacklinks.String()}
// Tag is not added to details of object explicitly as it is not system relation
s.SetDetail(bundle.RelationKeyTag, domain.StringList([]string{}))
}
s.SetDetail(bundle.RelationKeyFeaturedRelations.String(), pbtypes.StringList(fr))
s.SetDetail(bundle.RelationKeyFeaturedRelations, domain.StringList(fr))
}
}
var WithAddedFeaturedRelation = func(key domain.RelationKey) StateTransformer {
return func(s *state.State) {
var featRels = pbtypes.GetStringList(s.Details(), bundle.RelationKeyFeaturedRelations.String())
featRels := s.Details().GetStringList(bundle.RelationKeyFeaturedRelations)
if slice.FindPos(featRels, key.String()) > -1 {
return
} else {
s.SetDetail(bundle.RelationKeyFeaturedRelations.String(), pbtypes.StringList(append(featRels, key.String())))
s.SetDetail(bundle.RelationKeyFeaturedRelations, domain.StringList(append(featRels, key.String())))
}
}
}
var WithRemovedFeaturedRelation = func(key domain.RelationKey) StateTransformer {
return func(s *state.State) {
var featRels = pbtypes.GetStringList(s.Details(), bundle.RelationKeyFeaturedRelations.String())
var featRels = s.Details().GetStringList(bundle.RelationKeyFeaturedRelations)
if slice.FindPos(featRels, key.String()) > -1 {
s.SetDetail(bundle.RelationKeyFeaturedRelations.String(), pbtypes.StringList(slice.RemoveMut(featRels, key.String())))
s.SetDetail(bundle.RelationKeyFeaturedRelations, domain.StringList(slice.RemoveMut(featRels, key.String())))
return
}
}
}
var WithCreatorRemovedFromFeaturedRelations = StateTransformer(func(s *state.State) {
fr := pbtypes.GetStringList(s.Details(), bundle.RelationKeyFeaturedRelations.String())
fr := s.Details().GetStringList(bundle.RelationKeyFeaturedRelations)
if slice.FindPos(fr, bundle.RelationKeyCreator.String()) != -1 {
frc := make([]string, len(fr))
copy(frc, fr)
frc = slice.RemoveMut(frc, bundle.RelationKeyCreator.String())
s.SetDetail(bundle.RelationKeyFeaturedRelations.String(), pbtypes.StringList(frc))
s.SetDetail(bundle.RelationKeyFeaturedRelations, domain.StringList(frc))
}
})
@ -276,8 +278,8 @@ var WithForcedDescription = func(s *state.State) {
RequireHeader(s)
var align model.BlockAlign
if pbtypes.HasField(s.Details(), bundle.RelationKeyLayoutAlign.String()) {
alignN := int(pbtypes.GetFloat64(s.Details(), bundle.RelationKeyLayoutAlign.String()))
if s.Details().Has(bundle.RelationKeyLayoutAlign) {
alignN := int(s.Details().GetFloat64(bundle.RelationKeyLayoutAlign))
if alignN >= 0 && alignN <= 2 {
align = model.BlockAlign(alignN)
}
@ -365,11 +367,11 @@ var WithNoDescription = StateTransformer(func(s *state.State) {
var WithNameToFirstBlock = StateTransformer(func(s *state.State) {
RequireHeader(s)
name, ok := s.Details().Fields[bundle.RelationKeyName.String()]
if ok && name.GetStringValue() != "" {
name, ok := s.Details().TryString(bundle.RelationKeyName)
if ok && name != "" {
newBlock := simple.New(&model.Block{
Content: &model.BlockContentOfText{
Text: &model.BlockContentText{Text: name.GetStringValue()},
Text: &model.BlockContentText{Text: name},
},
})
s.Add(newBlock)
@ -377,7 +379,7 @@ var WithNameToFirstBlock = StateTransformer(func(s *state.State) {
if err := s.InsertTo(HeaderLayoutId, model.Block_Bottom, newBlock.Model().Id); err != nil {
log.Errorf("WithNameToFirstBlock failed to insert: %s", err)
} else {
s.RemoveDetail(bundle.RelationKeyName.String())
s.RemoveDetail(bundle.RelationKeyName)
}
}
})
@ -386,8 +388,8 @@ var WithFeaturedRelations = StateTransformer(func(s *state.State) {
RequireHeader(s)
var align model.BlockAlign
if pbtypes.HasField(s.Details(), bundle.RelationKeyLayoutAlign.String()) {
alignN := int(pbtypes.GetFloat64(s.Details(), bundle.RelationKeyLayoutAlign.String()))
if s.Details().Has(bundle.RelationKeyLayoutAlign) {
alignN := int(s.Details().GetFloat64(bundle.RelationKeyLayoutAlign))
if alignN >= 0 && alignN <= 2 {
align = model.BlockAlign(alignN)
}
@ -493,45 +495,6 @@ var WithDataview = func(dataview *model.BlockContentOfDataview, forceViews bool)
return WithDataviewID(DataviewBlockId, dataview, forceViews)
}
var WithNoRootLink = func(targetBlockId string) StateTransformer {
return func(s *state.State) {
var linkBlockId string
s.Iterate(func(b simple.Block) (isContinue bool) {
if b, ok := b.(*link.Link); !ok {
return true
} else {
if b.Model().GetLink().TargetBlockId == targetBlockId {
linkBlockId = b.Id
return false
}
return true
}
})
if linkBlockId == "" {
return
}
s.Unlink(linkBlockId)
return
}
}
func WithBlockField(blockId, fieldName string, value *types.Value) StateTransformer {
return func(s *state.State) {
if b := s.Get(blockId); b != nil {
fields := b.Model().Fields
if fields == nil || fields.Fields == nil {
fields = &types.Struct{Fields: map[string]*types.Value{}}
}
fields.Fields[fieldName] = value
b.Model().Fields = fields
}
}
}
func InitTemplate(s *state.State, templates ...StateTransformer) {
for _, template := range templates {
template(s)
@ -595,8 +558,8 @@ var oldBookmarkRelationBlocks = []string{
bundle.RelationKeyCreatedDate.String(),
}
var oldBookmarkRelations = []string{
bundle.RelationKeyUrl.String(),
var oldBookmarkRelations = []domain.RelationKey{
bundle.RelationKeyUrl,
}
func makeRelationBlock(k string) *model.Block {
@ -612,7 +575,8 @@ func makeRelationBlock(k string) *model.Block {
var WithBookmarkBlocks = func(s *state.State) {
if !s.HasRelation(bundle.RelationKeySource.String()) && s.HasRelation(bundle.RelationKeyUrl.String()) {
s.SetDetailAndBundledRelation(bundle.RelationKeySource, s.Details().Fields[bundle.RelationKeyUrl.String()])
url := s.Details().GetString(bundle.RelationKeyUrl)
s.SetDetailAndBundledRelation(bundle.RelationKeySource, domain.String(url))
}
for _, oldRel := range oldBookmarkRelationBlocks {
@ -623,11 +587,11 @@ var WithBookmarkBlocks = func(s *state.State) {
s.RemoveRelation(oldRel)
}
fr := pbtypes.GetStringList(s.Details(), bundle.RelationKeyFeaturedRelations.String())
fr := s.Details().GetStringList(bundle.RelationKeyFeaturedRelations)
if slice.FindPos(fr, bundle.RelationKeyCreatedDate.String()) == -1 {
fr = append(fr, bundle.RelationKeyCreatedDate.String())
s.SetDetail(bundle.RelationKeyFeaturedRelations.String(), pbtypes.StringList(fr))
s.SetDetail(bundle.RelationKeyFeaturedRelations, domain.StringList(fr))
}
for _, k := range bookmarkRelationKeys {

View file

@ -13,7 +13,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
type WidgetObject struct {
@ -55,7 +54,7 @@ func (w *WidgetObject) CreationStateMigration(ctx *smartblock.InitContext) migra
template.InitTemplate(st,
template.WithEmpty,
template.WithObjectTypesAndLayout([]domain.TypeKey{bundle.TypeKeyDashboard}, model.ObjectType_dashboard),
template.WithDetail(bundle.RelationKeyIsHidden, pbtypes.Bool(true)),
template.WithDetail(bundle.RelationKeyIsHidden, domain.Bool(true)),
)
},
}

View file

@ -79,10 +79,10 @@ func (w *Workspaces) initTemplate(ctx *smartblock.InitContext) {
template.WithEmpty,
template.WithTitle,
template.WithFeaturedRelations,
template.WithDetail(bundle.RelationKeyIsHidden, pbtypes.Bool(true)),
template.WithForcedDetail(bundle.RelationKeyLayout, pbtypes.Float64(float64(model.ObjectType_space))),
template.WithDetail(bundle.RelationKeyIsHidden, domain.Bool(true)),
template.WithForcedDetail(bundle.RelationKeyLayout, domain.Int64(model.ObjectType_space)),
template.WithForcedObjectTypes([]domain.TypeKey{bundle.TypeKeySpace}),
template.WithForcedDetail(bundle.RelationKeyFeaturedRelations, pbtypes.StringList([]string{bundle.RelationKeyType.String(), bundle.RelationKeyCreator.String()})),
template.WithForcedDetail(bundle.RelationKeyFeaturedRelations, domain.StringList([]string{bundle.RelationKeyType.String(), bundle.RelationKeyCreator.String()})),
)
}
@ -98,23 +98,23 @@ func (w *Workspaces) CreationStateMigration(ctx *smartblock.InitContext) migrati
func (w *Workspaces) SetInviteFileInfo(fileCid string, fileKey string) (err error) {
st := w.NewState()
st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteFileCid, pbtypes.String(fileCid))
st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteFileKey, pbtypes.String(fileKey))
st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteFileCid, domain.String(fileCid))
st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteFileKey, domain.String(fileKey))
return w.Apply(st)
}
func (w *Workspaces) GetExistingInviteInfo() (fileCid string, fileKey string) {
details := w.CombinedDetails()
fileCid = pbtypes.GetString(details, bundle.RelationKeySpaceInviteFileCid.String())
fileKey = pbtypes.GetString(details, bundle.RelationKeySpaceInviteFileKey.String())
fileCid = details.GetString(bundle.RelationKeySpaceInviteFileCid)
fileKey = details.GetString(bundle.RelationKeySpaceInviteFileKey)
return
}
func (w *Workspaces) RemoveExistingInviteInfo() (fileCid string, err error) {
details := w.Details()
fileCid = pbtypes.GetString(details, bundle.RelationKeySpaceInviteFileCid.String())
fileCid = details.GetString(bundle.RelationKeySpaceInviteFileCid)
newState := w.NewState()
newState.RemoveDetail(bundle.RelationKeySpaceInviteFileCid.String(), bundle.RelationKeySpaceInviteFileKey.String())
newState.RemoveDetail(bundle.RelationKeySpaceInviteFileCid, bundle.RelationKeySpaceInviteFileKey)
return fileCid, w.Apply(newState)
}
@ -128,6 +128,6 @@ func (w *Workspaces) onApply(info smartblock.ApplyInfo) error {
}
func (w *Workspaces) onWorkspaceChanged(state *state.State) {
details := pbtypes.CopyStruct(state.CombinedDetails(), true)
details := state.CombinedDetails().Copy()
w.spaceService.OnWorkspaceChanged(w.SpaceID(), details)
}

View file

@ -14,7 +14,6 @@ import (
"github.com/anyproto/any-sync/app"
"github.com/globalsign/mgo/bson"
"github.com/gogo/protobuf/types"
"github.com/google/uuid"
"github.com/gosimple/slug"
"github.com/samber/lo"
@ -46,7 +45,6 @@ import (
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/anyerror"
"github.com/anyproto/anytype-heart/util/constant"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/text"
)
@ -145,7 +143,7 @@ func (e *export) sendNotification(err error, req pb.RpcObjectListExportRequest)
type exportContext struct {
spaceId string
docs map[string]*types.Struct
docs map[string]*domain.Details
includeArchive bool
includeNested bool
includeFiles bool
@ -162,7 +160,7 @@ func newExportContext(e *export, req pb.RpcObjectListExportRequest) *exportConte
return &exportContext{
path: req.Path,
spaceId: req.SpaceId,
docs: map[string]*types.Struct{},
docs: map[string]*domain.Details{},
includeArchive: req.IncludeArchived,
includeNested: req.IncludeNested,
includeFiles: req.IncludeFiles,
@ -328,12 +326,12 @@ func (e *exportContext) docsForExport() (err error) {
}
func (e *exportContext) getObjectsByIDs(isProtobuf bool) error {
res, err := e.queryAndFilterObjectsByRelation(e.spaceId, e.reqIds, bundle.RelationKeyId.String())
res, err := e.queryAndFilterObjectsByRelation(e.spaceId, e.reqIds, bundle.RelationKeyId)
if err != nil {
return err
}
for _, object := range res {
id := pbtypes.GetString(object.Details, bundle.RelationKeyId.String())
id := object.Details.GetString(bundle.RelationKeyId)
e.docs[id] = object.Details
}
if isProtobuf {
@ -342,18 +340,18 @@ func (e *exportContext) getObjectsByIDs(isProtobuf bool) error {
return e.processNotProtobuf()
}
func (e *exportContext) queryAndFilterObjectsByRelation(spaceId string, reqIds []string, relationFilter string) ([]database.Record, error) {
func (e *exportContext) queryAndFilterObjectsByRelation(spaceId string, reqIds []string, relationKey domain.RelationKey) ([]database.Record, error) {
var allObjects []database.Record
const singleBatchCount = 50
for j := 0; j < len(reqIds); {
if j+singleBatchCount < len(reqIds) {
records, err := e.queryObjectsByIds(spaceId, reqIds[j:j+singleBatchCount], relationFilter)
records, err := e.queryObjectsByIds(spaceId, reqIds[j:j+singleBatchCount], relationKey)
if err != nil {
return nil, err
}
allObjects = append(allObjects, records...)
} else {
records, err := e.queryObjectsByIds(spaceId, reqIds[j:], relationFilter)
records, err := e.queryObjectsByIds(spaceId, reqIds[j:], relationKey)
if err != nil {
return nil, err
}
@ -364,13 +362,13 @@ func (e *exportContext) queryAndFilterObjectsByRelation(spaceId string, reqIds [
return allObjects, nil
}
func (e *exportContext) queryObjectsByIds(spaceId string, reqIds []string, relationFilter string) ([]database.Record, error) {
func (e *exportContext) queryObjectsByIds(spaceId string, reqIds []string, relationKey domain.RelationKey) ([]database.Record, error) {
return e.objectStore.SpaceIndex(spaceId).Query(database.Query{
Filters: []*model.BlockContentDataviewFilter{
Filters: []database.FilterRequest{
{
RelationKey: relationFilter,
RelationKey: relationKey,
Condition: model.BlockContentDataviewFilter_In,
Value: pbtypes.StringList(reqIds),
Value: domain.StringList(reqIds),
},
},
})
@ -387,7 +385,7 @@ func (e *exportContext) processNotProtobuf() error {
}
if e.includeNested {
for _, id := range ids {
e.addNestedObject(id, map[string]*types.Struct{})
e.addNestedObject(id, map[string]*domain.Details{})
}
}
return nil
@ -461,7 +459,7 @@ func (e *exportContext) addDerivedObjects() error {
return nil
}
func (e *exportContext) getRelationsAndTypes(notProcessedObjects map[string]*types.Struct, processedObjects map[string]struct{}) ([]string, []string, []string, error) {
func (e *exportContext) getRelationsAndTypes(notProcessedObjects map[string]*domain.Details, processedObjects map[string]struct{}) ([]string, []string, []string, error) {
allRelations, allTypes, allSetOfList, err := e.collectDerivedObjects(notProcessedObjects)
if err != nil {
return nil, nil, nil, err
@ -480,7 +478,7 @@ func (e *exportContext) getRelationsAndTypes(notProcessedObjects map[string]*typ
return allRelations, allTypes, allSetOfList, nil
}
func (e *exportContext) collectDerivedObjects(objects map[string]*types.Struct) ([]string, []string, []string, error) {
func (e *exportContext) collectDerivedObjects(objects map[string]*domain.Details) ([]string, []string, []string, error) {
var relations, objectsTypes, setOf []string
for id := range objects {
err := cache.Do(e.picker, id, func(b sb.SmartBlock) error {
@ -494,9 +492,9 @@ func (e *exportContext) collectDerivedObjects(objects map[string]*types.Struct)
}
relations = lo.Union(relations, dataviewRelations)
}
objectTypeId := pbtypes.GetString(details, bundle.RelationKeyType.String())
objectTypeId := details.GetString(bundle.RelationKeyType)
objectsTypes = lo.Union(objectsTypes, []string{objectTypeId})
setOfList := pbtypes.GetStringList(details, bundle.RelationKeySetOf.String())
setOfList := details.GetStringList(bundle.RelationKeySetOf)
setOf = lo.Union(setOf, setOfList)
return nil
})
@ -516,9 +514,9 @@ func getObjectRelations(state *state.State) []string {
return relations
}
func isObjectWithDataview(details *types.Struct) bool {
return pbtypes.GetFloat64(details, bundle.RelationKeyLayout.String()) == float64(model.ObjectType_collection) ||
pbtypes.GetFloat64(details, bundle.RelationKeyLayout.String()) == float64(model.ObjectType_set)
func isObjectWithDataview(details *domain.Details) bool {
return details.GetInt64(bundle.RelationKeyLayout) == int64(model.ObjectType_collection) ||
details.GetInt64(bundle.RelationKeyLayout) == int64(model.ObjectType_set)
}
func getDataviewRelations(state *state.State) ([]string, error) {
@ -537,7 +535,7 @@ func getDataviewRelations(state *state.State) ([]string, error) {
}
func (e *exportContext) getDerivedObjectsForTypes(allTypes []string, processedObjects map[string]struct{}) ([]string, []string, []string, error) {
notProceedTypes := make(map[string]*types.Struct)
notProceedTypes := make(map[string]*domain.Details)
var relations, objectTypes []string
for _, object := range allTypes {
if _, ok := processedObjects[object]; ok {
@ -557,16 +555,16 @@ func (e *exportContext) getDerivedObjectsForTypes(allTypes []string, processedOb
}
func (e *exportContext) getTemplatesRelationsAndTypes(allTypes []string, processedObjects map[string]struct{}) ([]string, []string, []string, error) {
templates, err := e.queryAndFilterObjectsByRelation(e.spaceId, allTypes, bundle.RelationKeyTargetObjectType.String())
templates, err := e.queryAndFilterObjectsByRelation(e.spaceId, allTypes, bundle.RelationKeyTargetObjectType)
if err != nil {
return nil, nil, nil, err
}
if len(templates) == 0 {
return nil, nil, nil, nil
}
templatesToProcess := make(map[string]*types.Struct, len(templates))
templatesToProcess := make(map[string]*domain.Details, len(templates))
for _, template := range templates {
id := pbtypes.GetString(template.Details, bundle.RelationKeyId.String())
id := template.Details.GetString(bundle.RelationKeyId)
if _, ok := e.docs[id]; !ok {
e.docs[id] = template.Details
templatesToProcess[id] = template.Details
@ -615,7 +613,7 @@ func (e *exportContext) getRelationsFromStore(relations []string) ([]database.Re
}
uniqueKeys = append(uniqueKeys, uniqueKey.Marshal())
}
storeRelations, err := e.queryAndFilterObjectsByRelation(e.spaceId, uniqueKeys, bundle.RelationKeyUniqueKey.String())
storeRelations, err := e.queryAndFilterObjectsByRelation(e.spaceId, uniqueKeys, bundle.RelationKeyUniqueKey)
if err != nil {
return nil, err
}
@ -623,17 +621,16 @@ func (e *exportContext) getRelationsFromStore(relations []string) ([]database.Re
}
func (e *exportContext) addRelation(relation database.Record) {
if relationKey := pbtypes.GetString(relation.Details, bundle.RelationKeyRelationKey.String()); relationKey != "" {
if !bundle.HasRelation(relationKey) {
id := pbtypes.GetString(relation.Details, bundle.RelationKeyId.String())
e.docs[id] = relation.Details
}
relationKey := domain.RelationKey(relation.Details.GetString(bundle.RelationKeyRelationKey))
if relationKey != "" && !bundle.HasRelation(relationKey) {
id := relation.Details.GetString(bundle.RelationKeyId)
e.docs[id] = relation.Details
}
}
func (e *exportContext) addOptionIfTag(relation database.Record) error {
format := pbtypes.GetInt64(relation.Details, bundle.RelationKeyRelationFormat.String())
relationKey := pbtypes.GetString(relation.Details, bundle.RelationKeyRelationKey.String())
format := relation.Details.GetInt64(bundle.RelationKeyRelationFormat)
relationKey := relation.Details.GetString(bundle.RelationKeyRelationKey)
if format == int64(model.RelationFormat_tag) || format == int64(model.RelationFormat_status) {
err := e.addRelationOptions(relationKey)
if err != nil {
@ -649,7 +646,7 @@ func (e *exportContext) addRelationOptions(relationKey string) error {
return err
}
for _, option := range relationOptions {
id := pbtypes.GetString(option.Details, bundle.RelationKeyId.String())
id := option.Details.GetString(bundle.RelationKeyId)
e.docs[id] = option.Details
}
return nil
@ -657,16 +654,16 @@ func (e *exportContext) addRelationOptions(relationKey string) error {
func (e *exportContext) getRelationOptions(relationKey string) ([]database.Record, error) {
relationOptionsDetails, err := e.objectStore.SpaceIndex(e.spaceId).Query(database.Query{
Filters: []*model.BlockContentDataviewFilter{
Filters: []database.FilterRequest{
{
RelationKey: bundle.RelationKeyLayout.String(),
RelationKey: bundle.RelationKeyLayout,
Condition: model.BlockContentDataviewFilter_Equal,
Value: pbtypes.Int64(int64(model.ObjectType_relationOption)),
Value: domain.Int64(model.ObjectType_relationOption),
},
{
RelationKey: bundle.RelationKeyRelationKey.String(),
RelationKey: bundle.RelationKeyRelationKey,
Condition: model.BlockContentDataviewFilter_Equal,
Value: pbtypes.String(relationKey),
Value: domain.String(relationKey),
},
},
})
@ -677,7 +674,7 @@ func (e *exportContext) getRelationOptions(relationKey string) ([]database.Recor
}
func (e *exportContext) processObjectTypesAndSetOfList(objectTypes, setOfList []string) error {
objectDetails, err := e.queryAndFilterObjectsByRelation(e.spaceId, lo.Union(objectTypes, setOfList), bundle.RelationKeyId.String())
objectDetails, err := e.queryAndFilterObjectsByRelation(e.spaceId, lo.Union(objectTypes, setOfList), bundle.RelationKeyId)
if err != nil {
return err
}
@ -698,12 +695,12 @@ func (e *exportContext) processObjectTypesAndSetOfList(objectTypes, setOfList []
func (e *exportContext) addObjectsAndCollectRecommendedRelations(objectTypes []database.Record) ([]string, error) {
recommendedRelations := make([]string, 0, len(objectTypes))
for i := 0; i < len(objectTypes); i++ {
rawUniqueKey := pbtypes.GetString(objectTypes[i].Details, bundle.RelationKeyUniqueKey.String())
rawUniqueKey := objectTypes[i].Details.GetString(bundle.RelationKeyUniqueKey)
uniqueKey, err := domain.UnmarshalUniqueKey(rawUniqueKey)
if err != nil {
return nil, err
}
id := pbtypes.GetString(objectTypes[i].Details, bundle.RelationKeyId.String())
id := objectTypes[i].Details.GetString(bundle.RelationKeyId)
e.docs[id] = objectTypes[i].Details
if uniqueKey.SmartblockType() == smartblock.SmartBlockTypeObjectType {
key, err := domain.GetTypeKeyFromRawUniqueKey(rawUniqueKey)
@ -713,24 +710,24 @@ func (e *exportContext) addObjectsAndCollectRecommendedRelations(objectTypes []d
if bundle.IsInternalType(key) {
continue
}
recommendedRelations = append(recommendedRelations, pbtypes.GetStringList(objectTypes[i].Details, bundle.RelationKeyRecommendedRelations.String())...)
recommendedRelations = append(recommendedRelations, objectTypes[i].Details.GetStringList(bundle.RelationKeyRecommendedRelations)...)
}
}
return recommendedRelations, nil
}
func (e *exportContext) addRecommendedRelations(recommendedRelations []string) error {
relations, err := e.queryAndFilterObjectsByRelation(e.spaceId, recommendedRelations, bundle.RelationKeyId.String())
relations, err := e.queryAndFilterObjectsByRelation(e.spaceId, recommendedRelations, bundle.RelationKeyId)
if err != nil {
return err
}
for _, relation := range relations {
id := pbtypes.GetString(relation.Details, bundle.RelationKeyId.String())
id := relation.Details.GetString(bundle.RelationKeyId)
if id == addr.MissingObject {
continue
}
relationKey := pbtypes.GetString(relation.Details, bundle.RelationKeyUniqueKey.String())
relationKey := relation.Details.GetString(bundle.RelationKeyUniqueKey)
uniqueKey, err := domain.UnmarshalUniqueKey(relationKey)
if err != nil {
return err
@ -744,7 +741,7 @@ func (e *exportContext) addRecommendedRelations(recommendedRelations []string) e
}
func (e *exportContext) addNestedObjects(ids []string) error {
nestedDocs := make(map[string]*types.Struct, 0)
nestedDocs := make(map[string]*domain.Details, 0)
for _, id := range ids {
e.addNestedObject(id, nestedDocs)
}
@ -766,7 +763,7 @@ func (e *exportContext) addNestedObjects(ids []string) error {
return nil
}
func (e *exportContext) addNestedObject(id string, nestedDocs map[string]*types.Struct) {
func (e *exportContext) addNestedObject(id string, nestedDocs map[string]*domain.Details) {
links, err := e.objectStore.SpaceIndex(e.spaceId).GetOutboundLinksById(id)
if err != nil {
log.Errorf("export failed to get outbound links for id: %s", err)
@ -802,11 +799,11 @@ func (e *exportContext) fillLinkedFiles(id string) ([]string, error) {
err := cache.Do(e.picker, id, func(b sb.SmartBlock) error {
b.NewState().IterateLinkedFiles(func(fileObjectId string) {
res, err := spaceIndex.Query(database.Query{
Filters: []*model.BlockContentDataviewFilter{
Filters: []database.FilterRequest{
{
RelationKey: bundle.RelationKeyId.String(),
RelationKey: bundle.RelationKeyId,
Condition: model.BlockContentDataviewFilter_Equal,
Value: pbtypes.String(fileObjectId),
Value: domain.String(fileObjectId),
},
},
})
@ -841,11 +838,11 @@ func (e *exportContext) getExistedObjects(isProtobuf bool) error {
}
res = append(res, archivedObjects...)
}
e.docs = make(map[string]*types.Struct, len(res))
e.docs = make(map[string]*domain.Details, len(res))
for _, info := range res {
objectSpaceID := e.spaceId
if objectSpaceID == "" {
objectSpaceID = pbtypes.GetString(info.Details, bundle.RelationKeySpaceId.String())
objectSpaceID = info.Details.GetString(bundle.RelationKeySpaceId)
}
sbType, err := e.sbtProvider.Type(objectSpaceID, info.Id)
if err != nil {
@ -863,7 +860,7 @@ func (e *exportContext) getExistedObjects(isProtobuf bool) error {
func (e *exportContext) listTargetTypesFromTemplates(ids []string) []string {
for id, object := range e.docs {
if pbtypes.Get(object, bundle.RelationKeyTargetObjectType.String()) != nil {
if object.Has(bundle.RelationKeyTargetObjectType) {
ids = append(ids, id)
}
}
@ -881,7 +878,7 @@ func (e *exportContext) writeMultiDoc(ctx context.Context, mw converter.MultiCon
if err != nil {
return fmt.Errorf("save file: %w", err)
}
st.SetDetailAndBundledRelation(bundle.RelationKeySource, pbtypes.String(fileName))
st.SetDetailAndBundledRelation(bundle.RelationKeySource, domain.String(fileName))
}
if err = mw.Add(b.Space(), st); err != nil {
return err
@ -909,7 +906,7 @@ func (e *exportContext) writeMultiDoc(ctx context.Context, mw converter.MultiCon
func (e *exportContext) writeDoc(ctx context.Context, wr writer, docId string) (err error) {
return cache.Do(e.picker, docId, func(b sb.SmartBlock) error {
st := b.NewState()
if pbtypes.GetBool(st.CombinedDetails(), bundle.RelationKeyIsDeleted.String()) {
if st.CombinedDetails().GetBool(bundle.RelationKeyIsDeleted) {
return nil
}
@ -918,7 +915,7 @@ func (e *exportContext) writeDoc(ctx context.Context, wr writer, docId string) (
if err != nil {
return fmt.Errorf("save file: %w", err)
}
st.SetDetailAndBundledRelation(bundle.RelationKeySource, pbtypes.String(fileName))
st.SetDetailAndBundledRelation(bundle.RelationKeySource, domain.String(fileName))
// Don't save file objects in markdown
if e.format == model.Export_Markdown {
return nil
@ -944,7 +941,7 @@ func (e *exportContext) writeDoc(ctx context.Context, wr writer, docId string) (
} else {
filename = makeFileName(docId, e.spaceId, conv.Ext(), st, b.Type())
}
lastModifiedDate := pbtypes.GetInt64(st.LocalDetails(), bundle.RelationKeyLastModifiedDate.String())
lastModifiedDate := st.LocalDetails().GetInt64(bundle.RelationKeyLastModifiedDate)
if err = wr.WriteFile(filename, bytes.NewReader(result), lastModifiedDate); err != nil {
return err
}
@ -955,7 +952,7 @@ func (e *exportContext) writeDoc(ctx context.Context, wr writer, docId string) (
func (e *exportContext) saveFile(ctx context.Context, wr writer, fileObject sb.SmartBlock, exportAllSpaces bool) (fileName string, err error) {
fullId := domain.FullFileId{
SpaceId: fileObject.Space().Id(),
FileId: domain.FileId(pbtypes.GetString(fileObject.Details(), bundle.RelationKeyFileId.String())),
FileId: domain.FileId(fileObject.Details().GetString(bundle.RelationKeyFileId)),
}
file, err := e.fileService.FileByHash(ctx, fullId)
@ -997,7 +994,7 @@ func (e *exportContext) createProfileFile(spaceID string, wr writer) error {
return err
}
err = cache.Do(e.picker, spc.DerivedIDs().Workspace, func(b sb.SmartBlock) error {
spaceDashBoardID = pbtypes.GetString(b.CombinedDetails(), bundle.RelationKeySpaceDashboardId.String())
spaceDashBoardID = b.CombinedDetails().GetString(bundle.RelationKeySpaceDashboardId)
return nil
})
if err != nil {
@ -1022,14 +1019,14 @@ func (e *exportContext) createProfileFile(spaceID string, wr writer) error {
}
func makeMarkdownName(s *state.State, wr writer, docID, ext, spaceId string) string {
name := pbtypes.GetString(s.Details(), bundle.RelationKeyName.String())
name := s.Details().GetString(bundle.RelationKeyName)
if name == "" {
name = s.Snippet()
}
path := ""
// space can be empty in case user want to export all spaces
if spaceId == "" {
spaceId := pbtypes.GetString(s.LocalDetails(), bundle.RelationKeySpaceId.String())
spaceId := s.LocalDetails().GetString(bundle.RelationKeySpaceId)
path = filepath.Join(spaceDirectory, spaceId)
}
return wr.Namer().Get(path, docID, name, ext)
@ -1040,7 +1037,7 @@ func makeFileName(docId, spaceId, ext string, st *state.State, blockType smartbl
filename := filepath.Join(dir, docId+ext)
// space can be empty in case user want to export all spaces
if spaceId == "" {
spaceId := pbtypes.GetString(st.LocalDetails(), bundle.RelationKeySpaceId.String())
spaceId := st.LocalDetails().GetString(bundle.RelationKeySpaceId)
filename = filepath.Join(spaceDirectory, spaceId, filename)
}
return filename
@ -1063,11 +1060,11 @@ func provideFileDirectory(blockType smartblock.SmartBlockType) string {
}
}
func objectValid(sbType smartblock.SmartBlockType, info *model.ObjectInfo, includeArchived bool, isProtobuf bool) bool {
func objectValid(sbType smartblock.SmartBlockType, info *database.ObjectInfo, includeArchived bool, isProtobuf bool) bool {
if info.Id == addr.AnytypeProfileId {
return false
}
if !isProtobuf && !validTypeForNonProtobuf(sbType) && !validLayoutForNonProtobuf(info.Details) {
if !isProtobuf && (!validTypeForNonProtobuf(sbType) || !validLayoutForNonProtobuf(info.Details)) {
return false
}
if isProtobuf && !validType(sbType) {
@ -1076,7 +1073,7 @@ func objectValid(sbType smartblock.SmartBlockType, info *model.ObjectInfo, inclu
if strings.HasPrefix(info.Id, addr.BundledObjectTypeURLPrefix) || strings.HasPrefix(info.Id, addr.BundledRelationURLPrefix) {
return false
}
if pbtypes.GetBool(info.Details, bundle.RelationKeyIsArchived.String()) && !includeArchived {
if info.Details.GetBool(bundle.RelationKeyIsArchived) && !includeArchived {
return false
}
return true
@ -1123,10 +1120,8 @@ func (fn *namer) Get(path, hash, title, ext string) (name string) {
}
func validType(sbType smartblock.SmartBlockType) bool {
return sbType == smartblock.SmartBlockTypeHome ||
sbType == smartblock.SmartBlockTypeProfilePage ||
return sbType == smartblock.SmartBlockTypeProfilePage ||
sbType == smartblock.SmartBlockTypePage ||
sbType == smartblock.SmartBlockTypeSubObject ||
sbType == smartblock.SmartBlockTypeTemplate ||
sbType == smartblock.SmartBlockTypeWorkspace ||
sbType == smartblock.SmartBlockTypeWidget ||
@ -1143,9 +1138,9 @@ func validTypeForNonProtobuf(sbType smartblock.SmartBlockType) bool {
sbType == smartblock.SmartBlockTypeFileObject
}
func validLayoutForNonProtobuf(details *types.Struct) bool {
return pbtypes.GetFloat64(details, bundle.RelationKeyLayout.String()) != float64(model.ObjectType_collection) &&
pbtypes.GetFloat64(details, bundle.RelationKeyLayout.String()) != float64(model.ObjectType_set)
func validLayoutForNonProtobuf(details *domain.Details) bool {
return details.GetInt64(bundle.RelationKeyLayout) != int64(model.ObjectType_collection) &&
details.GetInt64(bundle.RelationKeyLayout) != int64(model.ObjectType_set)
}
func cleanupFile(wr writer) {
@ -1153,7 +1148,7 @@ func cleanupFile(wr writer) {
os.Remove(wr.Path())
}
func listObjectIds(docs map[string]*types.Struct) []string {
func listObjectIds(docs map[string]*domain.Details) []string {
ids := make([]string, 0, len(docs))
for id := range docs {
ids = append(ids, id)
@ -1162,5 +1157,5 @@ func listObjectIds(docs map[string]*types.Struct) []string {
}
func isLinkedObjectExist(rec []database.Record) bool {
return len(rec) > 0 && !pbtypes.GetBool(rec[0].Details, bundle.RelationKeyIsDeleted.String())
return len(rec) > 0 && !rec[0].Details.GetBool(bundle.RelationKeyIsDeleted)
}

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,6 @@ import (
"fmt"
"time"
"github.com/gogo/protobuf/types"
"github.com/google/uuid"
"github.com/anyproto/anytype-heart/core/block/collection"
@ -12,11 +11,11 @@ import (
"github.com/anyproto/anytype-heart/core/block/editor/template"
"github.com/anyproto/anytype-heart/core/block/simple"
simpleDataview "github.com/anyproto/anytype-heart/core/block/simple/dataview"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
sb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
type ImportCollectionSetting struct {
@ -73,7 +72,7 @@ func (r *ImportCollection) MakeImportCollection(req *ImportCollectionSetting) (*
}
}
detailsStruct = pbtypes.StructMerge(st.CombinedDetails(), detailsStruct, false)
detailsStruct = st.CombinedDetails().Merge(detailsStruct)
st.UpdateStoreSlice(template.CollectionStoreKey, req.targetObjects)
return r.getRootCollectionSnapshot(req.collectionName, st, detailsStruct, req.fileKeys), nil
@ -82,19 +81,19 @@ func (r *ImportCollection) MakeImportCollection(req *ImportCollectionSetting) (*
func (r *ImportCollection) getRootCollectionSnapshot(
collectionName string,
st *state.State,
detailsStruct *types.Struct,
detailsStruct *domain.Details,
fileKeys []*pb.ChangeFileKeys,
) *Snapshot {
if detailsStruct.GetFields() == nil {
detailsStruct = &types.Struct{Fields: map[string]*types.Value{}}
if detailsStruct == nil {
detailsStruct = domain.NewDetails()
}
detailsStruct.Fields[bundle.RelationKeyLayout.String()] = pbtypes.Int64(int64(model.ObjectType_collection))
detailsStruct.SetInt64(bundle.RelationKeyLayout, int64(model.ObjectType_collection))
return &Snapshot{
Id: uuid.New().String(),
FileName: collectionName,
SbType: sb.SmartBlockTypePage,
Snapshot: &pb.ChangeSnapshot{
Data: &model.SmartBlockSnapshotBase{
Snapshot: &SnapshotModel{
SbType: sb.SmartBlockTypePage,
Data: &StateSnapshot{
Blocks: st.Blocks(),
Details: detailsStruct,
ObjectTypes: []string{bundle.TypeKeyCollection.String()},
@ -125,16 +124,14 @@ func (r *ImportCollection) addRelations(st *state.State) error {
return nil
}
func (r *ImportCollection) getCreateCollectionRequest(collectionName string, icon string, shouldBeFavorite bool) *types.Struct {
details := make(map[string]*types.Value, 0)
details[bundle.RelationKeySourceFilePath.String()] = pbtypes.String(collectionName)
details[bundle.RelationKeyName.String()] = pbtypes.String(collectionName)
details[bundle.RelationKeyIsFavorite.String()] = pbtypes.Bool(shouldBeFavorite)
details[bundle.RelationKeyLayout.String()] = pbtypes.Float64(float64(model.ObjectType_collection))
details[bundle.RelationKeyIconImage.String()] = pbtypes.String(icon)
detailsStruct := &types.Struct{Fields: details}
return detailsStruct
func (r *ImportCollection) getCreateCollectionRequest(collectionName string, icon string, shouldBeFavorite bool) *domain.Details {
return domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeySourceFilePath: domain.String(collectionName),
bundle.RelationKeyName: domain.String(collectionName),
bundle.RelationKeyIsFavorite: domain.Bool(shouldBeFavorite),
bundle.RelationKeyLayout: domain.Int64(model.ObjectType_collection),
bundle.RelationKeyIconImage: domain.String(icon),
})
}
func ReplaceRelationsInDataView(st *state.State, rel *model.RelationLink) error {

View file

@ -8,7 +8,6 @@ import (
"strings"
"time"
"github.com/gogo/protobuf/types"
"github.com/ipfs/go-cid"
"github.com/anyproto/anytype-heart/core/block/editor/state"
@ -20,6 +19,7 @@ import (
"github.com/anyproto/anytype-heart/core/block/simple/file"
"github.com/anyproto/anytype-heart/core/block/simple/link"
"github.com/anyproto/anytype-heart/core/block/simple/text"
"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/logging"
@ -32,7 +32,7 @@ var randomIcons = []string{"📓", "📕", "📗", "📘", "📙", "📖", "📔
var log = logging.Logger("import")
func GetCommonDetails(sourcePath, name, emoji string, layout model.ObjectTypeLayout) *types.Struct {
func GetCommonDetails(sourcePath, name, emoji string, layout model.ObjectTypeLayout) *domain.Details {
creationTime, modTime := filetime.ExtractFileTimes(sourcePath)
if name == "" {
name = strings.TrimSuffix(filepath.Base(sourcePath), filepath.Ext(sourcePath))
@ -42,15 +42,14 @@ func GetCommonDetails(sourcePath, name, emoji string, layout model.ObjectTypeLay
}
h := sha256.Sum256([]byte(sourcePath))
hash := hex.EncodeToString(h[:])
fields := map[string]*types.Value{
bundle.RelationKeyName.String(): pbtypes.String(name),
bundle.RelationKeySourceFilePath.String(): pbtypes.String(hash),
bundle.RelationKeyIconEmoji.String(): pbtypes.String(emoji),
bundle.RelationKeyCreatedDate.String(): pbtypes.Int64(creationTime),
bundle.RelationKeyLastModifiedDate.String(): pbtypes.Int64(modTime),
bundle.RelationKeyLayout.String(): pbtypes.Float64(float64(layout)),
}
return &types.Struct{Fields: fields}
details := domain.NewDetails()
details.SetString(bundle.RelationKeyName, name)
details.SetString(bundle.RelationKeySourceFilePath, hash)
details.SetString(bundle.RelationKeyIconEmoji, emoji)
details.SetInt64(bundle.RelationKeyCreatedDate, creationTime)
details.SetInt64(bundle.RelationKeyLastModifiedDate, modTime)
details.SetInt64(bundle.RelationKeyLayout, int64(layout))
return details
}
func UpdateLinksToObjects(st *state.State, oldIDtoNew map[string]string) error {
@ -217,7 +216,7 @@ func isBundledObjects(targetObjectID string) bool {
return true
}
rel, err := pbtypes.RelationIdToKey(targetObjectID)
if err == nil && bundle.HasRelation(rel) {
if err == nil && bundle.HasRelation(domain.RelationKey(rel)) {
return true
}
@ -259,8 +258,8 @@ func handleTextBlock(oldIDtoNew map[string]string, block simple.Block, st *state
func UpdateObjectIDsInRelations(st *state.State, oldIDtoNew map[string]string) {
rels := st.GetRelationLinks()
for k, v := range st.Details().GetFields() {
relLink := rels.Get(k)
for k, v := range st.Details().Iterate() {
relLink := rels.Get(string(k))
if relLink == nil {
continue
}
@ -285,18 +284,17 @@ func isLinkToObject(relLink *model.RelationLink) bool {
relLink.Format == model.RelationFormat_file
}
func handleObjectRelation(st *state.State, oldIDtoNew map[string]string, v *types.Value, k string) {
if _, ok := v.GetKind().(*types.Value_StringValue); ok {
objectsID := v.GetStringValue()
newObjectIDs := getNewObjectsIDForRelation([]string{objectsID}, oldIDtoNew)
func handleObjectRelation(st *state.State, oldIDtoNew map[string]string, v domain.Value, k domain.RelationKey) {
if objectId, ok := v.TryString(); ok {
newObjectIDs := getNewObjectsIDForRelation([]string{objectId}, oldIDtoNew)
if len(newObjectIDs) != 0 {
st.SetDetail(k, pbtypes.String(newObjectIDs[0]))
st.SetDetail(k, domain.String(newObjectIDs[0]))
}
return
}
objectsIDs := pbtypes.GetStringListValue(v)
objectsIDs := v.StringList()
objectsIDs = getNewObjectsIDForRelation(objectsIDs, oldIDtoNew)
st.SetDetail(k, pbtypes.StringList(objectsIDs))
st.SetDetail(k, domain.StringList(objectsIDs))
}
func getNewObjectsIDForRelation(objectsIDs []string, oldIDtoNew map[string]string) []string {

View file

@ -4,11 +4,11 @@ package mock_objectcreator
import (
common "github.com/anyproto/anytype-heart/core/block/import/common"
domain "github.com/anyproto/anytype-heart/core/domain"
mock "github.com/stretchr/testify/mock"
objectcreator "github.com/anyproto/anytype-heart/core/block/import/common/objectcreator"
types "github.com/gogo/protobuf/types"
)
// MockService is an autogenerated mock type for the Service type
@ -25,24 +25,24 @@ func (_m *MockService) EXPECT() *MockService_Expecter {
}
// Create provides a mock function with given fields: dataObject, sn
func (_m *MockService) Create(dataObject *objectcreator.DataObject, sn *common.Snapshot) (*types.Struct, string, error) {
func (_m *MockService) Create(dataObject *objectcreator.DataObject, sn *common.Snapshot) (*domain.Details, string, error) {
ret := _m.Called(dataObject, sn)
if len(ret) == 0 {
panic("no return value specified for Create")
}
var r0 *types.Struct
var r0 *domain.Details
var r1 string
var r2 error
if rf, ok := ret.Get(0).(func(*objectcreator.DataObject, *common.Snapshot) (*types.Struct, string, error)); ok {
if rf, ok := ret.Get(0).(func(*objectcreator.DataObject, *common.Snapshot) (*domain.Details, string, error)); ok {
return rf(dataObject, sn)
}
if rf, ok := ret.Get(0).(func(*objectcreator.DataObject, *common.Snapshot) *types.Struct); ok {
if rf, ok := ret.Get(0).(func(*objectcreator.DataObject, *common.Snapshot) *domain.Details); ok {
r0 = rf(dataObject, sn)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*types.Struct)
r0 = ret.Get(0).(*domain.Details)
}
}
@ -80,12 +80,12 @@ func (_c *MockService_Create_Call) Run(run func(dataObject *objectcreator.DataOb
return _c
}
func (_c *MockService_Create_Call) Return(_a0 *types.Struct, _a1 string, _a2 error) *MockService_Create_Call {
func (_c *MockService_Create_Call) Return(_a0 *domain.Details, _a1 string, _a2 error) *MockService_Create_Call {
_c.Call.Return(_a0, _a1, _a2)
return _c
}
func (_c *MockService_Create_Call) RunAndReturn(run func(*objectcreator.DataObject, *common.Snapshot) (*types.Struct, string, error)) *MockService_Create_Call {
func (_c *MockService_Create_Call) RunAndReturn(run func(*objectcreator.DataObject, *common.Snapshot) (*domain.Details, string, error)) *MockService_Create_Call {
_c.Call.Return(run)
return _c
}

View file

@ -6,7 +6,6 @@ import (
"fmt"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/gogo/protobuf/types"
"github.com/samber/lo"
"go.uber.org/zap"
@ -41,7 +40,7 @@ var log = logging.Logger("import")
// Service encapsulate logic with creation of given smartblocks
type Service interface {
//nolint:lll
Create(dataObject *DataObject, sn *common.Snapshot) (*types.Struct, string, error)
Create(dataObject *DataObject, sn *common.Snapshot) (*domain.Details, string, error)
}
type ObjectGetterDeleter interface {
@ -79,7 +78,7 @@ func New(detailsService detailservice.Service,
}
// Create creates smart blocks from given snapshots
func (oc *ObjectCreator) Create(dataObject *DataObject, sn *common.Snapshot) (*types.Struct, string, error) {
func (oc *ObjectCreator) Create(dataObject *DataObject, sn *common.Snapshot) (*domain.Details, string, error) {
snapshot := sn.Snapshot.Data
oldIDtoNew := dataObject.oldIDtoNew
ctx := dataObject.ctx
@ -88,15 +87,15 @@ func (oc *ObjectCreator) Create(dataObject *DataObject, sn *common.Snapshot) (*t
newID := oldIDtoNew[sn.Id]
if sn.SbType == coresb.SmartBlockTypeFile {
if sn.Snapshot.SbType == coresb.SmartBlockTypeFile {
return nil, newID, nil
}
oc.setRootBlock(snapshot, newID)
oc.injectImportDetails(sn, origin)
st := state.NewDocFromSnapshot(newID, sn.Snapshot, state.WithUniqueKeyMigration(sn.SbType)).(*state.State)
st.SetLocalDetail(bundle.RelationKeyLastModifiedDate.String(), pbtypes.Int64(pbtypes.GetInt64(snapshot.Details, bundle.RelationKeyLastModifiedDate.String())))
st := state.NewDocFromSnapshot(newID, sn.Snapshot.ToProto()).(*state.State)
st.SetLocalDetail(bundle.RelationKeyLastModifiedDate, snapshot.Details.Get(bundle.RelationKeyLastModifiedDate))
var (
filesToDelete []string
@ -114,12 +113,12 @@ func (oc *ObjectCreator) Create(dataObject *DataObject, sn *common.Snapshot) (*t
}
oc.updateKeys(st, oldIDtoNew)
if sn.SbType == coresb.SmartBlockTypeWorkspace {
if sn.Snapshot.SbType == coresb.SmartBlockTypeWorkspace {
oc.setSpaceDashboardID(spaceID, st)
return nil, newID, nil
}
if sn.SbType == coresb.SmartBlockTypeWidget {
if sn.Snapshot.SbType == coresb.SmartBlockTypeWidget {
return oc.updateWidgetObject(st)
}
@ -132,7 +131,7 @@ func (oc *ObjectCreator) Create(dataObject *DataObject, sn *common.Snapshot) (*t
})
typeKeys := st.ObjectTypeKeys()
if sn.SbType == coresb.SmartBlockTypeObjectType {
if sn.Snapshot.SbType == coresb.SmartBlockTypeObjectType {
// we widen typeKeys here to install bundled templates for imported object type
typeKeys = append(typeKeys, domain.TypeKey(st.UniqueKeyInternal()))
}
@ -140,7 +139,7 @@ func (oc *ObjectCreator) Create(dataObject *DataObject, sn *common.Snapshot) (*t
if err != nil {
log.With("objectID", newID).Errorf("failed to install bundled relations and types: %s", err)
}
var respDetails *types.Struct
var respDetails *domain.Details
if payload := dataObject.createPayloads[newID]; payload.RootRawChange != nil {
respDetails, err = oc.createNewObject(ctx, spaceID, payload, st, newID, oldIDtoNew)
if err != nil {
@ -148,7 +147,7 @@ func (oc *ObjectCreator) Create(dataObject *DataObject, sn *common.Snapshot) (*t
return nil, "", err
}
} else {
if canUpdateObject(sn.SbType) {
if canUpdateObject(sn.Snapshot.SbType) {
respDetails = oc.updateExistingObject(st, oldIDtoNew, newID)
}
}
@ -174,11 +173,11 @@ func canUpdateObject(sbType coresb.SmartBlockType) bool {
}
func (oc *ObjectCreator) injectImportDetails(sn *common.Snapshot, origin objectorigin.ObjectOrigin) {
lastModifiedDate := pbtypes.GetInt64(sn.Snapshot.Data.Details, bundle.RelationKeyLastModifiedDate.String())
createdDate := pbtypes.GetInt64(sn.Snapshot.Data.Details, bundle.RelationKeyCreatedDate.String())
lastModifiedDate := sn.Snapshot.Data.Details.GetInt64(bundle.RelationKeyLastModifiedDate)
createdDate := sn.Snapshot.Data.Details.GetInt64(bundle.RelationKeyCreatedDate)
if lastModifiedDate == 0 {
if createdDate != 0 {
sn.Snapshot.Data.Details.Fields[bundle.RelationKeyLastModifiedDate.String()] = pbtypes.Int64(int64(createdDate))
sn.Snapshot.Data.Details.SetInt64(bundle.RelationKeyLastModifiedDate, createdDate)
} else {
// we can't fallback to time.Now() because it will be inconsistent with the time used in object tree header.
// So instead we should EXPLICITLY set creation date to the snapshot in all importers
@ -191,12 +190,12 @@ func (oc *ObjectCreator) injectImportDetails(sn *common.Snapshot, origin objecto
sn.Snapshot.Data.OriginalCreatedTimestamp = createdDate
}
sn.Snapshot.Data.Details.Fields[bundle.RelationKeyOrigin.String()] = pbtypes.Int64(int64(origin.Origin))
sn.Snapshot.Data.Details.Fields[bundle.RelationKeyImportType.String()] = pbtypes.Int64(int64(origin.ImportType))
sn.Snapshot.Data.Details.SetInt64(bundle.RelationKeyOrigin, int64(origin.Origin))
sn.Snapshot.Data.Details.SetInt64(bundle.RelationKeyImportType, int64(origin.ImportType))
// we don't need to inject relatonLinks, they will be automatically injected for bundled relations
}
func (oc *ObjectCreator) updateExistingObject(st *state.State, oldIDtoNew map[string]string, newID string) *types.Struct {
func (oc *ObjectCreator) updateExistingObject(st *state.State, oldIDtoNew map[string]string, newID string) *domain.Details {
if st.Store() != nil {
oc.updateLinksInCollections(st, oldIDtoNew, false)
}
@ -214,7 +213,7 @@ func (oc *ObjectCreator) installBundledRelationsAndTypes(
idsToCheck := make([]string, 0, len(links)+len(objectTypeKeys))
for _, link := range links {
// TODO: check if we have them in oldIDtoNew
if !bundle.HasRelation(link.Key) {
if !bundle.HasRelation(domain.RelationKey(link.Key)) {
continue
}
@ -243,8 +242,8 @@ func (oc *ObjectCreator) createNewObject(
payload treestorage.TreeStorageCreatePayload,
st *state.State,
newID string,
oldIDtoNew map[string]string) (*types.Struct, error) {
var respDetails *types.Struct
oldIDtoNew map[string]string) (*domain.Details, error) {
var respDetails *domain.Details
spc, err := oc.spaceService.Get(ctx, spaceID)
if err != nil {
return nil, fmt.Errorf("get space %s: %w", spaceID, err)
@ -282,7 +281,7 @@ func (oc *ObjectCreator) createNewObject(
return respDetails, nil
}
func (oc *ObjectCreator) setRootBlock(snapshot *model.SmartBlockSnapshotBase, newID string) {
func (oc *ObjectCreator) setRootBlock(snapshot *common.StateSnapshot, newID string) {
var found bool
for _, b := range snapshot.Blocks {
if b.Id == newID {
@ -323,28 +322,28 @@ func (oc *ObjectCreator) deleteFile(spaceId string, hash string) {
func (oc *ObjectCreator) setSpaceDashboardID(spaceID string, st *state.State) {
// hand-pick relation because space is a special case
var details []*model.Detail
spaceDashBoardID := pbtypes.GetString(st.CombinedDetails(), bundle.RelationKeySpaceDashboardId.String())
if spaceDashBoardID != "" {
details = append(details, &model.Detail{
Key: bundle.RelationKeySpaceDashboardId.String(),
Value: pbtypes.String(spaceDashBoardID),
var details []domain.Detail
ids := st.CombinedDetails().GetStringList(bundle.RelationKeySpaceDashboardId)
if len(ids) > 0 {
details = append(details, domain.Detail{
Key: bundle.RelationKeySpaceDashboardId,
Value: domain.StringList(ids),
})
}
spaceName := pbtypes.GetString(st.CombinedDetails(), bundle.RelationKeyName.String())
spaceName := st.CombinedDetails().GetString(bundle.RelationKeyName)
if spaceName != "" {
details = append(details, &model.Detail{
Key: bundle.RelationKeyName.String(),
Value: pbtypes.String(spaceName),
details = append(details, domain.Detail{
Key: bundle.RelationKeyName,
Value: domain.String(spaceName),
})
}
iconOption := pbtypes.GetInt64(st.CombinedDetails(), bundle.RelationKeyIconOption.String())
iconOption := st.CombinedDetails().GetInt64(bundle.RelationKeyIconOption)
if iconOption != 0 {
details = append(details, &model.Detail{
Key: bundle.RelationKeyIconOption.String(),
Value: pbtypes.Int64(iconOption),
details = append(details, domain.Detail{
Key: bundle.RelationKeyIconOption,
Value: domain.Int64(iconOption),
})
}
if len(details) > 0 {
@ -365,8 +364,8 @@ func (oc *ObjectCreator) setSpaceDashboardID(spaceID string, st *state.State) {
}
}
func (oc *ObjectCreator) resetState(newID string, st *state.State) *types.Struct {
var respDetails *types.Struct
func (oc *ObjectCreator) resetState(newID string, st *state.State) *domain.Details {
var respDetails *domain.Details
err := cache.Do(oc.objectGetterDeleter, newID, func(b smartblock.SmartBlock) error {
err := history.ResetToVersion(b, st)
if err != nil {
@ -389,8 +388,8 @@ func (oc *ObjectCreator) resetState(newID string, st *state.State) *types.Struct
return respDetails
}
func (oc *ObjectCreator) setFavorite(snapshot *model.SmartBlockSnapshotBase, newID string) {
isFavorite := pbtypes.GetBool(snapshot.Details, bundle.RelationKeyIsFavorite.String())
func (oc *ObjectCreator) setFavorite(snapshot *common.StateSnapshot, newID string) {
isFavorite := snapshot.Details.GetBool(bundle.RelationKeyIsFavorite)
if isFavorite {
err := oc.detailsService.SetIsFavorite(newID, true, false)
if err != nil {
@ -399,8 +398,8 @@ func (oc *ObjectCreator) setFavorite(snapshot *model.SmartBlockSnapshotBase, new
}
}
func (oc *ObjectCreator) setArchived(snapshot *model.SmartBlockSnapshotBase, newID string) {
isArchive := pbtypes.GetBool(snapshot.Details, bundle.RelationKeyIsArchived.String())
func (oc *ObjectCreator) setArchived(snapshot *common.StateSnapshot, newID string) {
isArchive := snapshot.Details.GetBool(bundle.RelationKeyIsArchived)
if isArchive {
err := oc.detailsService.SetIsArchived(newID, true)
if err != nil {
@ -472,7 +471,7 @@ func (oc *ObjectCreator) mergeCollections(existedObjects []string, st *state.Sta
st.UpdateStoreSlice(template.CollectionStoreKey, result)
}
func (oc *ObjectCreator) updateWidgetObject(st *state.State) (*types.Struct, string, error) {
func (oc *ObjectCreator) updateWidgetObject(st *state.State) (*domain.Details, string, error) {
err := cache.DoState(oc.objectGetterDeleter, st.RootId(), func(oldState *state.State, sb smartblock.SmartBlock) error {
blocks := st.Blocks()
blocksMap := make(map[string]*model.Block, len(blocks))
@ -542,32 +541,31 @@ func (oc *ObjectCreator) getExistingWidgetsTargetIDs(oldState *state.State) (map
}
func (oc *ObjectCreator) updateKeys(st *state.State, oldIDtoNew map[string]string) {
for key, value := range st.Details().GetFields() {
if newKey, ok := oldIDtoNew[key]; ok && newKey != key {
oc.updateDetails(st, newKey, value, key)
for key, value := range st.Details().Iterate() {
if newKey, ok := oldIDtoNew[string(key)]; ok && newKey != string(key) {
oc.updateDetails(st, domain.RelationKey(newKey), value, key)
}
}
if newKey, ok := oldIDtoNew[st.ObjectTypeKey().String()]; ok {
st.SetObjectTypeKey(domain.TypeKey(newKey))
}
}
func (oc *ObjectCreator) updateDetails(st *state.State, newKey string, value *types.Value, key string) {
func (oc *ObjectCreator) updateDetails(st *state.State, newKey domain.RelationKey, value domain.Value, key domain.RelationKey) {
st.SetDetail(newKey, value)
link := oc.findRelationLinkByKey(st, key)
if link != nil {
link.Key = newKey
link.Key = string(newKey)
st.AddRelationLinks(link)
}
st.RemoveRelation(key)
}
func (oc *ObjectCreator) findRelationLinkByKey(st *state.State, key string) *model.RelationLink {
func (oc *ObjectCreator) findRelationLinkByKey(st *state.State, key domain.RelationKey) *model.RelationLink {
relationLinks := st.GetRelationLinks()
var link *model.RelationLink
for _, link = range relationLinks {
if link.Key == key {
if domain.RelationKey(link.Key) == key {
break
}
}

View file

@ -6,7 +6,6 @@ import (
"testing"
"github.com/anyproto/any-sync/app"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/anyproto/anytype-heart/core/block/detailservice/mock_detailservice"
@ -17,13 +16,11 @@ import (
"github.com/anyproto/anytype-heart/core/block/object/objectcreator"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/domain/objectorigin"
"github.com/anyproto/anytype-heart/pb"
"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/pb/model"
"github.com/anyproto/anytype-heart/space/clientspace/mock_clientspace"
"github.com/anyproto/anytype-heart/space/mock_space"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
func TestObjectCreator_Create(t *testing.T) {
@ -44,33 +41,32 @@ func TestObjectCreator_Create(t *testing.T) {
oldToNew := map[string]string{importedSpaceIdParticipantId: participantId}
dataObject := NewDataObject(context.Background(), oldToNew, nil, objectorigin.Import(model.Import_Pb), spaceID)
sn := &common.Snapshot{
Id: importedSpaceIdParticipantId,
SbType: coresb.SmartBlockTypeParticipant,
Snapshot: &pb.ChangeSnapshot{
Data: &model.SmartBlockSnapshotBase{
Details: &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyId.String(): pbtypes.String(importedSpaceIdParticipantId),
bundle.RelationKeyIdentity.String(): pbtypes.String(identity),
bundle.RelationKeySpaceId.String(): pbtypes.String(importedSpaceId),
bundle.RelationKeyLastModifiedBy.String(): pbtypes.String(identity),
bundle.RelationKeyParticipantPermissions.String(): pbtypes.Int64(int64(model.ParticipantPermissions_Reader)),
bundle.RelationKeyParticipantStatus.String(): pbtypes.Int64(int64(model.ParticipantStatus_Active)),
},
},
Id: importedSpaceIdParticipantId,
Snapshot: &common.SnapshotModel{
SbType: coresb.SmartBlockTypeParticipant,
Data: &common.StateSnapshot{
Details: domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyId: domain.String(importedSpaceIdParticipantId),
bundle.RelationKeyIdentity: domain.String(identity),
bundle.RelationKeySpaceId: domain.String(importedSpaceId),
bundle.RelationKeyLastModifiedBy: domain.String(identity),
bundle.RelationKeyParticipantPermissions: domain.Int64(int64(model.ParticipantPermissions_Reader)),
bundle.RelationKeyParticipantStatus: domain.Int64(int64(model.ParticipantStatus_Active)),
}),
},
},
}
testParticipant := smarttest.New(participantId)
st := testParticipant.NewState()
testDetails := &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyId.String(): pbtypes.String(participantId),
bundle.RelationKeyIdentity.String(): pbtypes.String(identity),
bundle.RelationKeySpaceId.String(): pbtypes.String(spaceID),
bundle.RelationKeyLastModifiedBy.String(): pbtypes.String(identity),
bundle.RelationKeyParticipantPermissions.String(): pbtypes.Int64(int64(model.ParticipantPermissions_Owner)),
bundle.RelationKeyParticipantStatus.String(): pbtypes.Int64(int64(model.ParticipantStatus_Active)),
}}
testDetails := domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyId: domain.String(participantId),
bundle.RelationKeyIdentity: domain.String(identity),
bundle.RelationKeySpaceId: domain.String(spaceID),
bundle.RelationKeyLastModifiedBy: domain.String(identity),
bundle.RelationKeyParticipantPermissions: domain.Int64(int64(model.ParticipantPermissions_Owner)),
bundle.RelationKeyParticipantStatus: domain.Int64(int64(model.ParticipantStatus_Active)),
})
st.SetDetails(testDetails)
err := testParticipant.Apply(st)
assert.Nil(t, err)
@ -98,9 +94,9 @@ func TestObjectCreator_updateKeys(t *testing.T) {
oc := ObjectCreator{}
oldToNew := map[string]string{"oldId": "newId", "oldKey": "newKey"}
doc := state.NewDoc("oldId", nil).(*state.State)
doc.SetDetails(&types.Struct{Fields: map[string]*types.Value{
"oldKey": pbtypes.String("test"),
}})
doc.SetDetails(domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
"oldKey": domain.String("test"),
}))
doc.AddRelationLinks(&model.RelationLink{
Key: "oldKey",
})
@ -108,8 +104,8 @@ func TestObjectCreator_updateKeys(t *testing.T) {
oc.updateKeys(doc, oldToNew)
// then
assert.Nil(t, doc.Details().GetFields()["oldKey"])
assert.Equal(t, pbtypes.String("test"), doc.Details().GetFields()["newKey"])
assert.False(t, doc.Details().Has("oldKey"))
assert.Equal(t, domain.String("test"), doc.Details().Get("newKey"))
assert.True(t, doc.HasRelation("newKey"))
})
t.Run("updateKeys - update object type key", func(t *testing.T) {
@ -135,7 +131,7 @@ func TestObjectCreator_updateKeys(t *testing.T) {
oc.updateKeys(doc, oldToNew)
// then
assert.Nil(t, doc.Details().GetFields()["newKey"])
assert.False(t, doc.Details().Has("newKey"))
assert.Equal(t, domain.TypeKey(""), doc.ObjectTypeKey())
})
t.Run("keys are the same", func(t *testing.T) {
@ -143,9 +139,9 @@ func TestObjectCreator_updateKeys(t *testing.T) {
oc := ObjectCreator{}
oldToNew := map[string]string{"oldId": "newId", "key": "key"}
doc := state.NewDoc("oldId", nil).(*state.State)
doc.SetDetails(&types.Struct{Fields: map[string]*types.Value{
"key": pbtypes.String("test"),
}})
doc.SetDetails(domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
"key": domain.String("test"),
}))
doc.AddRelationLinks(&model.RelationLink{
Key: "key",
})
@ -153,7 +149,7 @@ func TestObjectCreator_updateKeys(t *testing.T) {
oc.updateKeys(doc, oldToNew)
// then
assert.Equal(t, pbtypes.String("test"), doc.Details().GetFields()["key"])
assert.Equal(t, "test", doc.Details().GetString("key"))
assert.True(t, doc.HasRelation("key"))
})
}

View file

@ -4,9 +4,9 @@ import (
"context"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/import/common"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/domain/objectorigin"
)
@ -21,7 +21,7 @@ type DataObject struct {
}
type Result struct {
Details *types.Struct
Details *domain.Details
NewID string
Err error
}

View file

@ -18,7 +18,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
type derivedObject struct {
@ -44,21 +43,21 @@ func (d *derivedObject) GetIDAndPayload(ctx context.Context, spaceID string, sn
}
return id, payload, nil
}
rawUniqueKey := pbtypes.GetString(sn.Snapshot.Data.Details, bundle.RelationKeyUniqueKey.String())
rawUniqueKey := sn.Snapshot.Data.Details.GetString(bundle.RelationKeyUniqueKey)
uniqueKey, err := domain.UnmarshalUniqueKey(rawUniqueKey)
if err != nil {
uniqueKey, err = domain.NewUniqueKey(sn.SbType, sn.Snapshot.Data.Key)
uniqueKey, err = domain.NewUniqueKey(sn.Snapshot.SbType, sn.Snapshot.Data.Key)
if err != nil {
return "", treestorage.TreeStorageCreatePayload{}, fmt.Errorf("create unique key from %s and %q: %w", sn.SbType, sn.Snapshot.Data.Key, err)
return "", treestorage.TreeStorageCreatePayload{}, fmt.Errorf("create unique key from %s and %q: %w", sn.Snapshot.SbType, sn.Snapshot.Data.Key, err)
}
}
var key string
if d.isDeletedObject(spaceID, uniqueKey.Marshal()) {
key = bson.NewObjectId().Hex()
uniqueKey, err = domain.NewUniqueKey(sn.SbType, key)
uniqueKey, err = domain.NewUniqueKey(sn.Snapshot.SbType, key)
if err != nil {
return "", treestorage.TreeStorageCreatePayload{}, fmt.Errorf("create unique key from %s: %w", sn.SbType, err)
return "", treestorage.TreeStorageCreatePayload{}, fmt.Errorf("create unique key from %s: %w", sn.Snapshot.SbType, err)
}
}
d.internalKey = key
@ -80,16 +79,16 @@ func (d *derivedObject) GetInternalKey(sbType sb.SmartBlockType) string {
func (d *derivedObject) isDeletedObject(spaceId string, uniqueKey string) bool {
ids, _, err := d.objectStore.SpaceIndex(spaceId).QueryObjectIds(database.Query{
Filters: []*model.BlockContentDataviewFilter{
Filters: []database.FilterRequest{
{
Condition: model.BlockContentDataviewFilter_Equal,
RelationKey: bundle.RelationKeyUniqueKey.String(),
Value: pbtypes.String(uniqueKey),
RelationKey: bundle.RelationKeyUniqueKey,
Value: domain.String(uniqueKey),
},
{
Condition: model.BlockContentDataviewFilter_Equal,
RelationKey: bundle.RelationKeyIsDeleted.String(),
Value: pbtypes.Bool(true),
RelationKey: bundle.RelationKeyIsDeleted,
Value: domain.Bool(true),
},
},
})
@ -98,16 +97,16 @@ func (d *derivedObject) isDeletedObject(spaceId string, uniqueKey string) bool {
func (d *derivedObject) getInternalKey(spaceID, objectId string) (string, error) {
ids, err := d.objectStore.SpaceIndex(spaceID).Query(database.Query{
Filters: []*model.BlockContentDataviewFilter{
Filters: []database.FilterRequest{
{
Condition: model.BlockContentDataviewFilter_Equal,
RelationKey: bundle.RelationKeyId.String(),
Value: pbtypes.String(objectId),
RelationKey: bundle.RelationKeyId,
Value: domain.String(objectId),
},
},
})
if err == nil && len(ids) > 0 {
uniqueKey := pbtypes.GetString(ids[0].Details, bundle.RelationKeyUniqueKey.String())
uniqueKey := ids[0].Details.GetString(bundle.RelationKeyUniqueKey)
key, err := domain.UnmarshalUniqueKey(uniqueKey)
if err != nil {
return "", nil

View file

@ -7,21 +7,18 @@ import (
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/anyproto/anytype-heart/core/block/import/common"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/domain/objectorigin"
"github.com/anyproto/anytype-heart/pb"
"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/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/clientspace/mock_clientspace"
"github.com/anyproto/anytype-heart/space/mock_space"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
func TestDerivedObject_GetIDAndPayload(t *testing.T) {
@ -32,15 +29,15 @@ func TestDerivedObject_GetIDAndPayload(t *testing.T) {
deriveObject := newDerivedObject(newExistingObject(sf), service, sf)
sn := &common.Snapshot{
Id: "oldId",
Snapshot: &pb.ChangeSnapshot{
Data: &model.SmartBlockSnapshotBase{
Details: &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyUniqueKey.String(): pbtypes.String("key"),
}},
Snapshot: &common.SnapshotModel{
Data: &common.StateSnapshot{
Details: domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyUniqueKey: domain.String("key"),
}),
Key: "oldKey",
},
SbType: coresb.SmartBlockTypePage,
},
SbType: coresb.SmartBlockTypePage,
}
space := mock_clientspace.NewMockSpace(t)
service.EXPECT().Get(context.Background(), "spaceId").Return(space, nil)
@ -52,9 +49,9 @@ func TestDerivedObject_GetIDAndPayload(t *testing.T) {
assert.Nil(t, err)
sf.AddObjects(t, "spaceId", []objectstore.TestObject{
{
bundle.RelationKeyUniqueKey: pbtypes.String(uniqueKey.Marshal()),
bundle.RelationKeyId: pbtypes.String("oldId"),
bundle.RelationKeyIsDeleted: pbtypes.Bool(true),
bundle.RelationKeyUniqueKey: domain.String(uniqueKey.Marshal()),
bundle.RelationKeyId: domain.String("oldId"),
bundle.RelationKeyIsDeleted: domain.Bool(true),
},
})
@ -63,7 +60,7 @@ func TestDerivedObject_GetIDAndPayload(t *testing.T) {
// then
assert.Nil(t, err)
assert.NotEqual(t, deriveObject.GetInternalKey(sn.SbType), "key")
assert.NotEqual(t, deriveObject.GetInternalKey(sn.Snapshot.SbType), "key")
assert.Equal(t, "newId", id)
})
t.Run("existing object", func(t *testing.T) {
@ -73,27 +70,27 @@ func TestDerivedObject_GetIDAndPayload(t *testing.T) {
deriveObject := newDerivedObject(newExistingObject(sf), service, sf)
sn := &common.Snapshot{
Id: "oldId",
Snapshot: &pb.ChangeSnapshot{
Data: &model.SmartBlockSnapshotBase{
Details: &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyName.String(): pbtypes.String("name"),
bundle.RelationKeyRelationFormat.String(): pbtypes.Int64(int64(model.RelationFormat_number)),
}},
Snapshot: &common.SnapshotModel{
Data: &common.StateSnapshot{
Details: domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyName: domain.String("name"),
bundle.RelationKeyRelationFormat: domain.Int64(int64(model.RelationFormat_number)),
}),
},
SbType: coresb.SmartBlockTypeRelation,
},
SbType: coresb.SmartBlockTypeRelation,
}
uniqueKey, err := domain.NewUniqueKey(coresb.SmartBlockTypeRelation, "oldKey")
assert.Nil(t, err)
sf.AddObjects(t, "spaceId", []objectstore.TestObject{
{
bundle.RelationKeyUniqueKey: pbtypes.String(uniqueKey.Marshal()),
bundle.RelationKeyId: pbtypes.String("oldId"),
bundle.RelationKeyName: pbtypes.String("name"),
bundle.RelationKeyRelationFormat: pbtypes.Int64(int64(model.RelationFormat_number)),
bundle.RelationKeyLayout: pbtypes.Int64(int64(model.ObjectType_relation)),
bundle.RelationKeySpaceId: pbtypes.String("spaceId"),
bundle.RelationKeyUniqueKey: domain.String(uniqueKey.Marshal()),
bundle.RelationKeyId: domain.String("oldId"),
bundle.RelationKeyName: domain.String("name"),
bundle.RelationKeyRelationFormat: domain.Int64(int64(model.RelationFormat_number)),
bundle.RelationKeyLayout: domain.Int64(int64(model.ObjectType_relation)),
bundle.RelationKeySpaceId: domain.String("spaceId"),
},
})

View file

@ -7,12 +7,12 @@ import (
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/anytype-heart/core/block/import/common"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
sb "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/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
type existingObject struct {
@ -37,25 +37,25 @@ func (e *existingObject) GetIDAndPayload(_ context.Context, spaceID string, sn *
return id, treestorage.TreeStorageCreatePayload{}, nil
}
}
if sn.SbType == sb.SmartBlockTypeRelationOption {
if sn.Snapshot.SbType == sb.SmartBlockTypeRelationOption {
return e.getExistingRelationOption(sn, spaceID), treestorage.TreeStorageCreatePayload{}, nil
}
if sn.SbType == sb.SmartBlockTypeRelation {
if sn.Snapshot.SbType == sb.SmartBlockTypeRelation {
return e.getExistingRelation(sn, spaceID), treestorage.TreeStorageCreatePayload{}, nil
}
return "", treestorage.TreeStorageCreatePayload{}, nil
}
func (e *existingObject) getObjectByOldAnytypeID(spaceID string, sn *common.Snapshot) (string, error) {
oldAnytypeID := pbtypes.GetString(sn.Snapshot.Data.Details, bundle.RelationKeyOldAnytypeID.String())
oldAnytypeID := sn.Snapshot.Data.Details.GetString(bundle.RelationKeyOldAnytypeID)
// Check for imported objects
ids, _, err := e.objectStore.SpaceIndex(spaceID).QueryObjectIds(database.Query{
Filters: []*model.BlockContentDataviewFilter{
Filters: []database.FilterRequest{
{
Condition: model.BlockContentDataviewFilter_Equal,
RelationKey: bundle.RelationKeyOldAnytypeID.String(),
Value: pbtypes.String(oldAnytypeID),
RelationKey: bundle.RelationKeyOldAnytypeID,
Value: domain.String(oldAnytypeID),
},
},
})
@ -65,11 +65,11 @@ func (e *existingObject) getObjectByOldAnytypeID(spaceID string, sn *common.Snap
// Check for derived objects
ids, _, err = e.objectStore.SpaceIndex(spaceID).QueryObjectIds(database.Query{
Filters: []*model.BlockContentDataviewFilter{
Filters: []database.FilterRequest{
{
Condition: model.BlockContentDataviewFilter_Equal,
RelationKey: bundle.RelationKeyUniqueKey.String(),
Value: pbtypes.String(oldAnytypeID), // Old id equals to unique key
RelationKey: bundle.RelationKeyUniqueKey,
Value: domain.String(oldAnytypeID), // Old id equals to unique key
},
},
})
@ -81,13 +81,13 @@ func (e *existingObject) getObjectByOldAnytypeID(spaceID string, sn *common.Snap
}
func (e *existingObject) getExistingObject(spaceID string, sn *common.Snapshot) string {
source := pbtypes.GetString(sn.Snapshot.Data.Details, bundle.RelationKeySourceFilePath.String())
source := sn.Snapshot.Data.Details.GetString(bundle.RelationKeySourceFilePath)
ids, _, err := e.objectStore.SpaceIndex(spaceID).QueryObjectIds(database.Query{
Filters: []*model.BlockContentDataviewFilter{
Filters: []database.FilterRequest{
{
Condition: model.BlockContentDataviewFilter_Equal,
RelationKey: bundle.RelationKeySourceFilePath.String(),
Value: pbtypes.String(source),
RelationKey: bundle.RelationKeySourceFilePath,
Value: domain.String(source),
},
},
})
@ -98,24 +98,24 @@ func (e *existingObject) getExistingObject(spaceID string, sn *common.Snapshot)
}
func (e *existingObject) getExistingRelationOption(snapshot *common.Snapshot, spaceID string) string {
name := pbtypes.GetString(snapshot.Snapshot.Data.Details, bundle.RelationKeyName.String())
key := pbtypes.GetString(snapshot.Snapshot.Data.Details, bundle.RelationKeyRelationKey.String())
name := snapshot.Snapshot.Data.Details.GetString(bundle.RelationKeyName)
key := snapshot.Snapshot.Data.Details.GetString(bundle.RelationKeyRelationKey)
ids, _, err := e.objectStore.SpaceIndex(spaceID).QueryObjectIds(database.Query{
Filters: []*model.BlockContentDataviewFilter{
Filters: []database.FilterRequest{
{
Condition: model.BlockContentDataviewFilter_Equal,
RelationKey: bundle.RelationKeyName.String(),
Value: pbtypes.String(name),
RelationKey: bundle.RelationKeyName,
Value: domain.String(name),
},
{
Condition: model.BlockContentDataviewFilter_Equal,
RelationKey: bundle.RelationKeyRelationKey.String(),
Value: pbtypes.String(key),
RelationKey: bundle.RelationKeyRelationKey,
Value: domain.String(key),
},
{
Condition: model.BlockContentDataviewFilter_Equal,
RelationKey: bundle.RelationKeyLayout.String(),
Value: pbtypes.Int64(int64(model.ObjectType_relationOption)),
RelationKey: bundle.RelationKeyLayout,
Value: domain.Int64(model.ObjectType_relationOption),
},
},
})
@ -126,24 +126,24 @@ func (e *existingObject) getExistingRelationOption(snapshot *common.Snapshot, sp
}
func (e *existingObject) getExistingRelation(snapshot *common.Snapshot, spaceID string) string {
name := pbtypes.GetString(snapshot.Snapshot.Data.Details, bundle.RelationKeyName.String())
format := pbtypes.GetFloat64(snapshot.Snapshot.Data.Details, bundle.RelationKeyRelationFormat.String())
name := snapshot.Snapshot.Data.Details.GetString(bundle.RelationKeyName)
format := snapshot.Snapshot.Data.Details.GetFloat64(bundle.RelationKeyRelationFormat)
ids, _, err := e.objectStore.SpaceIndex(spaceID).QueryObjectIds(database.Query{
Filters: []*model.BlockContentDataviewFilter{
Filters: []database.FilterRequest{
{
Condition: model.BlockContentDataviewFilter_Equal,
RelationKey: bundle.RelationKeyName.String(),
Value: pbtypes.String(name),
RelationKey: bundle.RelationKeyName,
Value: domain.String(name),
},
{
Condition: model.BlockContentDataviewFilter_Equal,
RelationKey: bundle.RelationKeyRelationFormat.String(),
Value: pbtypes.Float64(format),
RelationKey: bundle.RelationKeyRelationFormat,
Value: domain.Float64(format),
},
{
Condition: model.BlockContentDataviewFilter_Equal,
RelationKey: bundle.RelationKeyLayout.String(),
Value: pbtypes.Int64(int64(model.ObjectType_relation)),
RelationKey: bundle.RelationKeyLayout,
Value: domain.Int64(model.ObjectType_relation),
},
},
})

View file

@ -11,7 +11,6 @@ import (
"github.com/anyproto/anytype-heart/core/block/import/common"
"github.com/anyproto/anytype-heart/core/domain/objectorigin"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
type fileObject struct {
@ -26,7 +25,7 @@ func (o *fileObject) GetIDAndPayload(ctx context.Context, spaceId string, sn *co
return "", treestorage.TreeStorageCreatePayload{}, err
}
filePath := pbtypes.GetString(sn.Snapshot.Data.Details, bundle.RelationKeySource.String())
filePath := sn.Snapshot.Data.Details.GetString(bundle.RelationKeySource)
if filePath != "" {
var encryptionKeys map[string]string
if sn.Snapshot.Data.FileInfo != nil {
@ -35,8 +34,7 @@ func (o *fileObject) GetIDAndPayload(ctx context.Context, spaceId string, sn *co
encryptionKeys[key.Path] = key.Key
}
}
name := pbtypes.GetString(sn.Snapshot.Data.Details, bundle.RelationKeyName.String())
fileObjectId, err := uploadFile(ctx, o.blockService, spaceId, name, filePath, origin, encryptionKeys)
fileObjectId, err := uploadFile(ctx, o.blockService, spaceId, filePath, origin, encryptionKeys, sn.Snapshot.Data.Details)
if err != nil {
log.Error("handling file object: upload file", zap.Error(err))
return id, payload, nil

View file

@ -7,7 +7,6 @@ import (
"time"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/gogo/protobuf/types"
"go.uber.org/zap"
"github.com/anyproto/anytype-heart/core/block"
@ -18,7 +17,6 @@ import (
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/filestore"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
// oldFile represents file in pre Files-as-Objects format
@ -29,7 +27,7 @@ type oldFile struct {
}
func (f *oldFile) GetIDAndPayload(ctx context.Context, spaceId string, sn *common.Snapshot, _ time.Time, _ bool, origin objectorigin.ObjectOrigin) (string, treestorage.TreeStorageCreatePayload, error) {
fileId := pbtypes.GetString(sn.Snapshot.Data.Details, bundle.RelationKeyId.String())
fileId := sn.Snapshot.Data.Details.GetString(bundle.RelationKeyId)
filesKeys := map[string]string{}
for _, fileKeys := range sn.Snapshot.FileKeys {
if fileKeys.Hash == fileId {
@ -38,10 +36,9 @@ func (f *oldFile) GetIDAndPayload(ctx context.Context, spaceId string, sn *commo
}
}
filePath := pbtypes.GetString(sn.Snapshot.Data.Details, bundle.RelationKeySource.String())
filePath := sn.Snapshot.Data.Details.GetString(bundle.RelationKeySource)
if filePath != "" {
name := pbtypes.GetString(sn.Snapshot.Data.Details, bundle.RelationKeyName.String())
fileObjectId, err := uploadFile(ctx, f.blockService, spaceId, name, filePath, origin, filesKeys)
fileObjectId, err := uploadFile(ctx, f.blockService, spaceId, filePath, origin, filesKeys, sn.Snapshot.Data.Details)
if err != nil {
log.Error("handling old file object: upload file", zap.Error(err))
}
@ -64,14 +61,17 @@ func (f *oldFile) GetIDAndPayload(ctx context.Context, spaceId string, sn *commo
return objectId, treestorage.TreeStorageCreatePayload{}, nil
}
func uploadFile(ctx context.Context, blockService *block.Service, spaceId string, name string, filePath string, origin objectorigin.ObjectOrigin, encryptionKeys map[string]string) (string, error) {
func uploadFile(
ctx context.Context,
blockService *block.Service,
spaceId, filePath string,
origin objectorigin.ObjectOrigin,
encryptionKeys map[string]string,
details *domain.Details,
) (string, error) {
params := pb.RpcFileUploadRequest{
SpaceId: spaceId,
Details: &types.Struct{
Fields: map[string]*types.Value{
bundle.RelationKeyName.String(): pbtypes.String(name),
},
},
Details: details.CopyOnlyKeys(bundle.RelationKeyName, bundle.RelationKeyIsHiddenDiscovery).ToProto(),
}
if strings.HasPrefix(filePath, "http://") || strings.HasPrefix(filePath, "https://") {

View file

@ -11,7 +11,6 @@ import (
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/domain/objectorigin"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
type participant struct{}
@ -21,7 +20,7 @@ func newParticipant() *participant {
}
func (w *participant) GetIDAndPayload(ctx context.Context, spaceID string, sn *common.Snapshot, _ time.Time, _ bool, _ objectorigin.ObjectOrigin) (string, treestorage.TreeStorageCreatePayload, error) {
participantId := pbtypes.GetString(sn.Snapshot.Data.Details, bundle.RelationKeyId.String())
participantId := sn.Snapshot.Data.Details.GetString(bundle.RelationKeyId)
splitId := strings.Split(participantId, "_")
identity := splitId[len(splitId)-1]
newParticipantID := domain.NewParticipantId(spaceID, identity)

Some files were not shown because too many files have changed in this diff Show more