mirror of
https://github.com/anyproto/anytype-heart.git
synced 2025-06-08 05:47:07 +09:00
GO-4459 Merge branch 'go-4144-fix-nested-filters' into go-4459-implement-first-stage-of-anytype-rest-api
This commit is contained in:
commit
1c1b9da344
7 changed files with 180 additions and 104 deletions
|
@ -4,6 +4,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -13,6 +14,7 @@ import (
|
|||
_ "net/http/pprof"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
@ -225,8 +227,25 @@ func main() {
|
|||
|
||||
startReportMemory(mw)
|
||||
|
||||
shutdown := func() {
|
||||
server.Stop()
|
||||
proxy.Close()
|
||||
mw.AppShutdown(context.Background(), &pb.RpcAppShutdownRequest{})
|
||||
}
|
||||
// do not change this, js client relies on this msg to ensure that server is up and parse address
|
||||
fmt.Println(grpcWebStartedMessagePrefix + webaddr)
|
||||
if runtime.GOOS == "windows" {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
for scanner.Scan() {
|
||||
message := scanner.Text()
|
||||
if message == "shutdown" {
|
||||
fmt.Println("[anytype-heart] Shutdown: received shutdown msg, closing components...")
|
||||
// Perform cleanup or exit
|
||||
shutdown()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// run rest api server
|
||||
var mwInternal core.MiddlewareInternal = mw
|
||||
|
@ -242,9 +261,8 @@ func main() {
|
|||
}
|
||||
continue
|
||||
}
|
||||
server.Stop()
|
||||
proxy.Close()
|
||||
mw.AppShutdown(context.Background(), &pb.RpcAppShutdownRequest{})
|
||||
fmt.Printf("[anytype-heart] Shutdown: received OS signal (%s), closing components...\n", sig.String())
|
||||
shutdown()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -274,7 +274,6 @@ func Bootstrap(a *app.App, components ...app.Component) {
|
|||
Register(recordsbatcher.New()).
|
||||
Register(configfetcher.New()).
|
||||
Register(process.New()).
|
||||
Register(core.New()).
|
||||
Register(core.NewTempDirService()).
|
||||
Register(treemanager.New()).
|
||||
Register(block.New()).
|
||||
|
|
|
@ -39,7 +39,14 @@ func New() *Middleware {
|
|||
}
|
||||
|
||||
func (mw *Middleware) AppShutdown(cctx context.Context, request *pb.RpcAppShutdownRequest) *pb.RpcAppShutdownResponse {
|
||||
mw.applicationService.Stop()
|
||||
err := mw.applicationService.Stop()
|
||||
// using fmt.Println instead of log because we want it only in stdout
|
||||
if err != nil {
|
||||
fmt.Println("[anytype-heart] Shutdown: error during closing components: ", err)
|
||||
} else {
|
||||
fmt.Println("[anytype-heart] Shutdown: graceful shutdown finished")
|
||||
}
|
||||
// intentionally do not pass the error to the client
|
||||
return &pb.RpcAppShutdownResponse{
|
||||
Error: &pb.RpcAppShutdownResponseError{
|
||||
Code: pb.RpcAppShutdownResponseError_NULL,
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/anyproto/any-sync/app"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
"github.com/anyproto/anytype-heart/metrics"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/logging"
|
||||
)
|
||||
|
||||
var log = logging.Logger("anytype-core")
|
||||
|
||||
const (
|
||||
CName = "anytype"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
Stop() error
|
||||
IsStarted() bool
|
||||
app.ComponentRunnable
|
||||
}
|
||||
|
||||
var _ app.Component = (*Anytype)(nil)
|
||||
|
||||
var _ Service = (*Anytype)(nil)
|
||||
|
||||
type Anytype struct {
|
||||
lock sync.RWMutex
|
||||
isStarted bool // use under the lock
|
||||
shutdownStartsCh chan struct {
|
||||
} // closed when node shutdown starts
|
||||
|
||||
}
|
||||
|
||||
func New() *Anytype {
|
||||
return &Anytype{
|
||||
shutdownStartsCh: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Anytype) Init(ap *app.App) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (a *Anytype) Name() string {
|
||||
return CName
|
||||
}
|
||||
|
||||
func (a *Anytype) Run(ctx context.Context) (err error) {
|
||||
a.start()
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: refactor to call tech space
|
||||
func (a *Anytype) IsStarted() bool {
|
||||
return true
|
||||
a.lock.Lock()
|
||||
defer a.lock.Unlock()
|
||||
|
||||
return a.isStarted
|
||||
}
|
||||
|
||||
func (a *Anytype) HandlePeerFound(p peer.AddrInfo) {
|
||||
// TODO: [MR] mdns
|
||||
}
|
||||
|
||||
func (a *Anytype) start() {
|
||||
a.lock.Lock()
|
||||
defer a.lock.Unlock()
|
||||
|
||||
if a.isStarted {
|
||||
return
|
||||
}
|
||||
|
||||
a.isStarted = true
|
||||
}
|
||||
|
||||
func (a *Anytype) Close(ctx context.Context) (err error) {
|
||||
metrics.Service.Close()
|
||||
return a.Stop()
|
||||
}
|
||||
|
||||
func (a *Anytype) Stop() error {
|
||||
fmt.Printf("stopping the library...\n")
|
||||
defer fmt.Println("library has been successfully stopped")
|
||||
a.lock.Lock()
|
||||
defer a.lock.Unlock()
|
||||
a.isStarted = false
|
||||
|
||||
if a.shutdownStartsCh != nil {
|
||||
close(a.shutdownStartsCh)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -8,8 +8,11 @@ import (
|
|||
"github.com/anyproto/any-sync/app"
|
||||
|
||||
"github.com/anyproto/anytype-heart/core/wallet"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/logging"
|
||||
)
|
||||
|
||||
var log = logging.Logger("anytype-core")
|
||||
|
||||
const tmpDir = "tmp"
|
||||
|
||||
type TempDirProvider interface {
|
||||
|
|
|
@ -190,6 +190,7 @@ func FiltersFromProto(filters []*model.BlockContentDataviewFilter) []FilterReque
|
|||
QuickOption: f.QuickOption,
|
||||
Format: f.Format,
|
||||
IncludeTime: f.IncludeTime,
|
||||
NestedFilters: FiltersFromProto(f.NestedFilters),
|
||||
})
|
||||
}
|
||||
return res
|
||||
|
|
|
@ -361,3 +361,150 @@ func Test_NewFilters(t *testing.T) {
|
|||
assert.Len(t, filters.FilterObj.(FiltersAnd)[0].(FiltersOr), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestFiltersFromProto(t *testing.T) {
|
||||
t.Run("no filters", func(t *testing.T) {
|
||||
// given
|
||||
var protoFilters []*model.BlockContentDataviewFilter
|
||||
|
||||
// when
|
||||
result := FiltersFromProto(protoFilters)
|
||||
|
||||
// then
|
||||
assert.NotNil(t, result)
|
||||
assert.Len(t, result, 0)
|
||||
})
|
||||
|
||||
t.Run("single filter without nesting", func(t *testing.T) {
|
||||
// given
|
||||
protoFilters := []*model.BlockContentDataviewFilter{
|
||||
{
|
||||
Id: "filter1",
|
||||
Operator: model.BlockContentDataviewFilter_No,
|
||||
RelationKey: "relationKey1",
|
||||
Condition: model.BlockContentDataviewFilter_Equal,
|
||||
Value: domain.String("value1").ToProto(),
|
||||
Format: model.RelationFormat_shorttext,
|
||||
},
|
||||
}
|
||||
|
||||
// when
|
||||
result := FiltersFromProto(protoFilters)
|
||||
|
||||
// then
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, "filter1", result[0].Id)
|
||||
assert.Equal(t, domain.RelationKey("relationKey1"), result[0].RelationKey)
|
||||
assert.Equal(t, model.BlockContentDataviewFilter_Equal, result[0].Condition)
|
||||
assert.Equal(t, domain.String("value1"), result[0].Value)
|
||||
assert.Equal(t, model.RelationFormat_shorttext, result[0].Format)
|
||||
assert.Empty(t, result[0].NestedFilters)
|
||||
})
|
||||
|
||||
t.Run("nested filters", func(t *testing.T) {
|
||||
// given
|
||||
protoFilters := []*model.BlockContentDataviewFilter{
|
||||
{
|
||||
Id: "filter1",
|
||||
Operator: model.BlockContentDataviewFilter_And,
|
||||
NestedFilters: []*model.BlockContentDataviewFilter{
|
||||
{
|
||||
Id: "nestedFilter1",
|
||||
Operator: model.BlockContentDataviewFilter_No,
|
||||
RelationKey: "relationKey2",
|
||||
Condition: model.BlockContentDataviewFilter_NotEqual,
|
||||
Value: domain.String("value2").ToProto(),
|
||||
Format: model.RelationFormat_date,
|
||||
},
|
||||
{
|
||||
Id: "nestedFilter2",
|
||||
Operator: model.BlockContentDataviewFilter_No,
|
||||
RelationKey: "relationKey3",
|
||||
Condition: model.BlockContentDataviewFilter_Equal,
|
||||
Value: domain.String("value3").ToProto(),
|
||||
Format: model.RelationFormat_status,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// when
|
||||
result := FiltersFromProto(protoFilters)
|
||||
|
||||
// then
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, "filter1", result[0].Id)
|
||||
assert.NotNil(t, result[0].NestedFilters)
|
||||
|
||||
nested := result[0].NestedFilters
|
||||
assert.Len(t, nested, 2)
|
||||
assert.Equal(t, "nestedFilter1", nested[0].Id)
|
||||
assert.Equal(t, domain.RelationKey("relationKey2"), nested[0].RelationKey)
|
||||
assert.Equal(t, model.BlockContentDataviewFilter_NotEqual, nested[0].Condition)
|
||||
assert.Equal(t, domain.String("value2"), nested[0].Value)
|
||||
assert.Equal(t, model.RelationFormat_date, nested[0].Format)
|
||||
assert.Equal(t, "nestedFilter2", nested[1].Id)
|
||||
assert.Equal(t, domain.RelationKey("relationKey3"), nested[1].RelationKey)
|
||||
assert.Equal(t, model.BlockContentDataviewFilter_Equal, nested[1].Condition)
|
||||
assert.Equal(t, domain.String("value3"), nested[1].Value)
|
||||
assert.Equal(t, model.RelationFormat_status, nested[1].Format)
|
||||
})
|
||||
|
||||
t.Run("deeply nested filters", func(t *testing.T) {
|
||||
// given
|
||||
protoFilters := []*model.BlockContentDataviewFilter{
|
||||
{
|
||||
Id: "filter1",
|
||||
Operator: model.BlockContentDataviewFilter_And,
|
||||
NestedFilters: []*model.BlockContentDataviewFilter{
|
||||
{
|
||||
Id: "nestedFilter1",
|
||||
Operator: model.BlockContentDataviewFilter_Or,
|
||||
NestedFilters: []*model.BlockContentDataviewFilter{
|
||||
{
|
||||
Id: "deepNestedFilter1",
|
||||
Operator: model.BlockContentDataviewFilter_No,
|
||||
RelationKey: "relationKey3",
|
||||
Condition: model.BlockContentDataviewFilter_Equal,
|
||||
Value: domain.String("value3").ToProto(),
|
||||
Format: model.RelationFormat_status,
|
||||
},
|
||||
{
|
||||
Id: "deepNestedFilter2",
|
||||
Operator: model.BlockContentDataviewFilter_No,
|
||||
RelationKey: "relationKey4",
|
||||
Condition: model.BlockContentDataviewFilter_NotEqual,
|
||||
Value: domain.String("value4").ToProto(),
|
||||
Format: model.RelationFormat_shorttext,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// when
|
||||
result := FiltersFromProto(protoFilters)
|
||||
|
||||
// then
|
||||
assert.Len(t, result, 1)
|
||||
assert.NotNil(t, result[0].NestedFilters)
|
||||
|
||||
nested := result[0].NestedFilters
|
||||
assert.Len(t, nested, 1)
|
||||
|
||||
deepNested := nested[0].NestedFilters
|
||||
assert.Len(t, deepNested, 2)
|
||||
assert.Equal(t, "deepNestedFilter1", deepNested[0].Id)
|
||||
assert.Equal(t, domain.RelationKey("relationKey3"), deepNested[0].RelationKey)
|
||||
assert.Equal(t, model.BlockContentDataviewFilter_Equal, deepNested[0].Condition)
|
||||
assert.Equal(t, domain.String("value3"), deepNested[0].Value)
|
||||
assert.Equal(t, model.RelationFormat_status, deepNested[0].Format)
|
||||
assert.Equal(t, "deepNestedFilter2", deepNested[1].Id)
|
||||
assert.Equal(t, domain.RelationKey("relationKey4"), deepNested[1].RelationKey)
|
||||
assert.Equal(t, model.BlockContentDataviewFilter_NotEqual, deepNested[1].Condition)
|
||||
assert.Equal(t, domain.String("value4"), deepNested[1].Value)
|
||||
assert.Equal(t, model.RelationFormat_shorttext, deepNested[1].Format)
|
||||
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue