Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(server): in-memory cache support for geojson #964

Open
wants to merge 2 commits into
base: feat/in-memory-cache-system-nlslayer
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions server/e2e/gql_nlslayer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -780,19 +780,23 @@ func addCustomProperties(
return requestBody, res
}

func TestCustomProperties(t *testing.T) {
mr, err := miniredis.Run()
if err != nil {
t.Fatal(err)
func customProperties(t *testing.T, isUseRedis bool) {
redisAddress := ""
if isUseRedis {
mr, err := miniredis.Run()
if err != nil {
t.Fatal(err)
}
defer mr.Close()
redisAddress = mr.Addr()
}
defer mr.Close()

e := StartServer(t, &config.Config{
Origins: []string{"https://example.com"},
AuthSrv: config.AuthSrvConfig{
Disabled: true,
},
RedisHost: mr.Addr(),
RedisHost: redisAddress,
}, true, baseSeeder)

pId := createProject(e)
Expand Down Expand Up @@ -862,3 +866,11 @@ func TestCustomProperties(t *testing.T) {
Value("customPropertySchema").Object().
Value("extrudedHeight").Equal(10)
}

func TestCustomProperties(t *testing.T) {
customProperties(t, false)
}

func TestCustomPropertiesWithRedis(t *testing.T) {
customProperties(t, true)
}
63 changes: 63 additions & 0 deletions server/internal/infrastructure/mongo/mongodoc/nlslayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mongodoc

import (
"errors"
"log"

"github.com/reearth/reearth/server/pkg/id"
"github.com/reearth/reearth/server/pkg/nlslayer"
Expand Down Expand Up @@ -536,6 +537,10 @@ func NewNLSLayerFeature(f nlslayer.Feature) NLSLayerFeatureDocument {
}

func NewNLSLayerGeometry(g nlslayer.Geometry) map[string]any {
if gMapFromRedis, ok := g.(map[string]any); ok {
return NewNLSLayerGeometryFromRedisMap(gMapFromRedis)
}

gMap := make(map[string]any)
switch g := g.(type) {
case *nlslayer.Point:
Expand All @@ -560,3 +565,61 @@ func NewNLSLayerGeometry(g nlslayer.Geometry) map[string]any {
}
return gMap
}

func NewNLSLayerGeometryFromRedisMap(redisMap map[string]any) map[string]any {
typeFields := []string{
"PointTypeField",
"LineStringTypeField",
"PolygonTypeField",
"MultiPolygonTypeField",
"GeometryCollectionTypeField",
}

var geometryType string
for _, field := range typeFields {
if typeVal, ok := redisMap[field]; ok {
geometryType = typeVal.(string)
break
}
}

if geometryType == "" {
log.Println("geometry type is missing")
return nil
}

gMap := make(map[string]any)
gMap["type"] = geometryType

if geometryType == "GeometryCollection" {
rawGeometries, ok := redisMap["GeometriesField"].([]any)
if !ok {
log.Println("invalid geometry collection data format")
return nil
}

gmapSlice := make([]map[string]any, 0, len(rawGeometries))
for _, rawGeometry := range rawGeometries {
geometry, ok := rawGeometry.(map[string]any)
if !ok {
log.Println("invalid geometry data format in collection")
continue
}

transformedGeometry := NewNLSLayerGeometryFromRedisMap(geometry)
if transformedGeometry != nil {
gmapSlice = append(gmapSlice, transformedGeometry)
}
}
gMap["geometries"] = gmapSlice
} else {
coords, ok := redisMap["CoordinatesField"]
if !ok {
log.Println("coordinates field is missing")
return nil
}
gMap["coordinates"] = coords
}

return gMap
}
89 changes: 89 additions & 0 deletions server/internal/infrastructure/mongo/mongodoc/nlslayer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,95 @@ func TestNewNLSLayerGeometry(t *testing.T) {
args: nlslayer.Geometry(nil),
want: map[string]any{},
},
{
name: "New point from redis map",
args: map[string]any{
"PointTypeField": "Point",
"CoordinatesField": []any{1, 2},
},
want: map[string]any{
"type": "Point",
"coordinates": []any{1, 2},
},
},
{
name: "New line string from redis map",
args: map[string]any{
"LineStringTypeField": "LineString",
"CoordinatesField": [][]any{{1, 2}, {3, 4}},
},
want: map[string]any{
"type": "LineString",
"coordinates": [][]any{{1, 2}, {3, 4}},
},
},
{
name: "New polygon from redis map",
args: map[string]any{
"PolygonTypeField": "Polygon",
"CoordinatesField": [][][]any{{{1, 2}, {3, 4}, {5, 6}, {1, 2}}},
},
want: map[string]any{
"type": "Polygon",
"coordinates": [][][]any{{{1, 2}, {3, 4}, {5, 6}, {1, 2}}},
},
},
{
name: "New multi polygon from redis map",
args: map[string]any{
"MultiPolygonTypeField": "MultiPolygon",
"CoordinatesField": [][][][]any{{{{1, 2}, {3, 4}, {5, 6}, {1, 2}}}},
},
want: map[string]any{
"type": "MultiPolygon",
"coordinates": [][][][]any{{{{1, 2}, {3, 4}, {5, 6}, {1, 2}}}},
},
},
{
name: "New geometry collection from redis map",
args: map[string]any{
"GeometryCollectionTypeField": "GeometryCollection",
"GeometriesField": []any{
map[string]any{
"PointTypeField": "Point",
"CoordinatesField": []any{1, 2},
},
map[string]any{
"LineStringTypeField": "LineString",
"CoordinatesField": [][]any{{1, 2}, {3, 4}},
},
map[string]any{
"PolygonTypeField": "Polygon",
"CoordinatesField": [][][]any{{{1, 2}, {3, 4}, {5, 6}, {1, 2}}},
},
map[string]any{
"MultiPolygonTypeField": "MultiPolygon",
"CoordinatesField": [][][][]any{{{{1, 2}, {3, 4}, {5, 6}, {1, 2}}}},
},
},
},
want: map[string]any{
"type": "GeometryCollection",
"geometries": []map[string]any{
{
"type": "Point",
"coordinates": []any{1, 2},
},
{
"type": "LineString",
"coordinates": [][]any{{1, 2}, {3, 4}},
},
{
"type": "Polygon",
"coordinates": [][][]any{{{1, 2}, {3, 4}, {5, 6}, {1, 2}}},
},
{
"type": "MultiPolygon",
"coordinates": [][][][]any{{{{1, 2}, {3, 4}, {5, 6}, {1, 2}}}},
},
},
},
},
}

for _, tt := range tests {
Expand Down
72 changes: 68 additions & 4 deletions server/internal/usecase/interactor/nlslayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -616,11 +616,21 @@ func (i *NLSLayer) AddCustomProperties(ctx context.Context, inp interfaces.AddCu
}
}()

layer, err := i.nlslayerRepo.FindByID(ctx, inp.LayerID)
var layer nlslayer.NLSLayer
layerSimple, err := getFromCache[*nlslayer.NLSLayerSimple](ctx, i.redis, nlslayer.NLSLayerCacheKey(inp.LayerID))
if err != nil {
return nil, err
}

if layerSimple == nil {
layer, err = i.nlslayerRepo.FindByID(ctx, inp.LayerID)
if err != nil {
return nil, err
}
} else {
layer = layerSimple
}

if layer.Sketch() == nil {
featureCollection := nlslayer.NewFeatureCollection(
"FeatureCollection",
Expand All @@ -643,6 +653,12 @@ func (i *NLSLayer) AddCustomProperties(ctx context.Context, inp interfaces.AddCu
}

tx.Commit()

err = setToCache[nlslayer.NLSLayer](ctx, i.redis, nlslayer.NLSLayerCacheKey(layer.ID()), layer)
if err != nil {
return nil, err
}

return layer, nil
}

Expand All @@ -659,11 +675,21 @@ func (i *NLSLayer) AddGeoJSONFeature(ctx context.Context, inp interfaces.AddNLSL
}
}()

layer, err := i.nlslayerRepo.FindByID(ctx, inp.LayerID)
var layer nlslayer.NLSLayer
layerSimple, err := getFromCache[*nlslayer.NLSLayerSimple](ctx, i.redis, nlslayer.NLSLayerCacheKey(inp.LayerID))
if err != nil {
return nlslayer.Feature{}, err
}

if layerSimple == nil {
layer, err = i.nlslayerRepo.FindByID(ctx, inp.LayerID)
if err != nil {
return nlslayer.Feature{}, err
}
} else {
layer = layerSimple
}

geometry, err := nlslayer.NewGeometryFromMap(inp.Geometry)
if err != nil {
return nlslayer.Feature{}, err
Expand Down Expand Up @@ -704,6 +730,12 @@ func (i *NLSLayer) AddGeoJSONFeature(ctx context.Context, inp interfaces.AddNLSL
}

tx.Commit()

err = setToCache[nlslayer.NLSLayer](ctx, i.redis, nlslayer.NLSLayerCacheKey(layer.ID()), layer)
if err != nil {
return nlslayer.Feature{}, err
}

return *feature, nil
}

Expand All @@ -720,11 +752,21 @@ func (i *NLSLayer) UpdateGeoJSONFeature(ctx context.Context, inp interfaces.Upda
}
}()

layer, err := i.nlslayerRepo.FindByID(ctx, inp.LayerID)
var layer nlslayer.NLSLayer
layerSimple, err := getFromCache[*nlslayer.NLSLayerSimple](ctx, i.redis, nlslayer.NLSLayerCacheKey(inp.LayerID))
if err != nil {
return nlslayer.Feature{}, err
}

if layerSimple == nil {
layer, err = i.nlslayerRepo.FindByID(ctx, inp.LayerID)
if err != nil {
return nlslayer.Feature{}, err
}
} else {
layer = layerSimple
}

if layer.Sketch() == nil || layer.Sketch().FeatureCollection() == nil || layer.Sketch().FeatureCollection().Features() == nil || len(layer.Sketch().FeatureCollection().Features()) == 0 {
return nlslayer.Feature{}, interfaces.ErrFeatureNotFound
}
Expand Down Expand Up @@ -756,6 +798,12 @@ func (i *NLSLayer) UpdateGeoJSONFeature(ctx context.Context, inp interfaces.Upda
}

tx.Commit()

err = setToCache[nlslayer.NLSLayer](ctx, i.redis, nlslayer.NLSLayerCacheKey(layer.ID()), layer)
if err != nil {
return nlslayer.Feature{}, err
}

return updatedFeature, nil
}

Expand All @@ -772,11 +820,21 @@ func (i *NLSLayer) DeleteGeoJSONFeature(ctx context.Context, inp interfaces.Dele
}
}()

layer, err := i.nlslayerRepo.FindByID(ctx, inp.LayerID)
var layer nlslayer.NLSLayer
layerSimple, err := getFromCache[*nlslayer.NLSLayerSimple](ctx, i.redis, nlslayer.NLSLayerCacheKey(inp.LayerID))
if err != nil {
return id.FeatureID{}, err
}

if layerSimple == nil {
layer, err = i.nlslayerRepo.FindByID(ctx, inp.LayerID)
if err != nil {
return id.FeatureID{}, err
}
} else {
layer = layerSimple
}

if layer.Sketch() == nil || layer.Sketch().FeatureCollection() == nil || layer.Sketch().FeatureCollection().Features() == nil || len(layer.Sketch().FeatureCollection().Features()) == 0 {
return id.FeatureID{}, interfaces.ErrFeatureNotFound
}
Expand All @@ -792,5 +850,11 @@ func (i *NLSLayer) DeleteGeoJSONFeature(ctx context.Context, inp interfaces.Dele
}

tx.Commit()

err = deleteFromCache(ctx, i.redis, nlslayer.NLSLayerCacheKey(layer.ID()))
if err != nil {
return id.FeatureID{}, err
}

return inp.FeatureID, nil
}
Loading