Skip to content

Commit

Permalink
Merge branch 'main' into feat-server/schemata-item-copy
Browse files Browse the repository at this point in the history
  • Loading branch information
mimoham24 authored Jan 15, 2025
2 parents 267c65b + c0a9ef2 commit 2e0c104
Show file tree
Hide file tree
Showing 6 changed files with 465 additions and 56 deletions.
67 changes: 26 additions & 41 deletions server/internal/adapter/integration/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package integration
import (
"context"
"errors"
"io"

"github.com/reearth/reearth-cms/server/internal/usecase"
"github.com/reearth/reearth-cms/server/pkg/model"
Expand Down Expand Up @@ -74,57 +73,50 @@ func (s *Server) ItemsAsGeoJSON(ctx context.Context, request ItemsAsGeoJSONReque
op := adapter.Operator(ctx)
uc := adapter.Usecases(ctx)

sp, err := uc.Schema.FindByModel(ctx, request.ModelId, op)
if err != nil {
return ItemsAsGeoJSON400Response{}, err
}

p := fromPagination(request.Params.Page, request.Params.PerPage)
items, _, err := uc.Item.FindBySchema(ctx, sp.Schema().ID(), nil, p, op)
schemaPackage, err := uc.Schema.FindByModel(ctx, request.ModelId, op)
if err != nil {
if errors.Is(err, rerror.ErrNotFound) {
return ItemsAsGeoJSON404Response{}, err
}
return ItemsAsGeoJSON400Response{}, err
}

fc, err := featureCollectionFromItems(items, sp.Schema())
featureCollections, err := uc.Item.ItemsAsGeoJSON(ctx, schemaPackage, request.Params.Page, request.Params.PerPage, op)
if err != nil {
if errors.Is(err, rerror.ErrNotFound) {
return ItemsAsGeoJSON404Response{}, err
}
return ItemsAsGeoJSON400Response{}, err
}

return ItemsAsGeoJSON200JSONResponse{
Features: fc.Features,
Type: fc.Type,
Features: featureCollections.FeatureCollections.Features,
Type: featureCollections.FeatureCollections.Type,
}, nil
}

func (s *Server) ItemsAsCSV(ctx context.Context, request ItemsAsCSVRequestObject) (ItemsAsCSVResponseObject, error) {
op := adapter.Operator(ctx)
uc := adapter.Usecases(ctx)

sp, err := uc.Schema.FindByModel(ctx, request.ModelId, op)
if err != nil {
return ItemsAsCSV400Response{}, err
}

p := fromPagination(request.Params.Page, request.Params.PerPage)
items, _, err := uc.Item.FindBySchema(ctx, sp.Schema().ID(), nil, p, op)
schemaPackage, err := uc.Schema.FindByModel(ctx, request.ModelId, op)
if err != nil {
if errors.Is(err, rerror.ErrNotFound) {
return ItemsAsCSV404Response{}, err
}
return ItemsAsCSV400Response{}, err
}

pr, pw := io.Pipe()
err = csvFromItems(pw, items, sp.Schema())
pr, err := uc.Item.ItemsAsCSV(ctx, schemaPackage, request.Params.Page, request.Params.PerPage, op)
if err != nil {
if errors.Is(err, rerror.ErrNotFound) {
return ItemsAsCSV404Response{}, err
}
return ItemsAsCSV400Response{}, err
}

return ItemsAsCSV200TextcsvResponse{
Body: pr,
Body: pr.PipeReader,
}, nil
}

Expand Down Expand Up @@ -217,28 +209,25 @@ func (s *Server) ItemsWithProjectAsGeoJSON(ctx context.Context, request ItemsWit
return ItemsWithProjectAsGeoJSON400Response{}, err
}

sp, err := uc.Schema.FindByModel(ctx, m.ID(), op)
if err != nil {
return ItemsWithProjectAsGeoJSON400Response{}, err
}

p := fromPagination(request.Params.Page, request.Params.PerPage)
items, _, err := uc.Item.FindBySchema(ctx, sp.Schema().ID(), nil, p, op)
schemaPackage, err := uc.Schema.FindByModel(ctx, m.ID(), op)
if err != nil {
if errors.Is(err, rerror.ErrNotFound) {
return ItemsWithProjectAsGeoJSON404Response{}, err
}
return ItemsWithProjectAsGeoJSON400Response{}, err
}

fc, err := featureCollectionFromItems(items, sp.Schema())
featureCollections, err := uc.Item.ItemsAsGeoJSON(ctx, schemaPackage, request.Params.Page, request.Params.PerPage, op)
if err != nil {
if errors.Is(err, rerror.ErrNotFound) {
return ItemsWithProjectAsGeoJSON404Response{}, err
}
return ItemsWithProjectAsGeoJSON400Response{}, err
}

return ItemsWithProjectAsGeoJSON200JSONResponse{
Features: fc.Features,
Type: fc.Type,
Features: featureCollections.FeatureCollections.Features,
Type: featureCollections.FeatureCollections.Type,
}, nil
}

Expand All @@ -262,28 +251,24 @@ func (s *Server) ItemsWithProjectAsCSV(ctx context.Context, request ItemsWithPro
return ItemsWithProjectAsCSV400Response{}, err
}

sp, err := uc.Schema.FindByModel(ctx, m.ID(), op)
if err != nil {
return ItemsWithProjectAsCSV400Response{}, err
}

p := fromPagination(request.Params.Page, request.Params.PerPage)
items, _, err := uc.Item.FindBySchema(ctx, sp.Schema().ID(), nil, p, op)
schemaPackage, err := uc.Schema.FindByModel(ctx, m.ID(), op)
if err != nil {
if errors.Is(err, rerror.ErrNotFound) {
return ItemsWithProjectAsCSV404Response{}, err
}
return ItemsWithProjectAsCSV400Response{}, err
}

pr, pw := io.Pipe()
err = csvFromItems(pw, items, sp.Schema())
pr, err := uc.Item.ItemsAsCSV(ctx, schemaPackage, request.Params.Page, request.Params.PerPage, op)
if err != nil {
if errors.Is(err, rerror.ErrNotFound) {
return ItemsWithProjectAsCSV404Response{}, err
}
return ItemsWithProjectAsCSV400Response{}, err
}

return ItemsWithProjectAsCSV200TextcsvResponse{
Body: pr,
Body: pr.PipeReader,
}, nil
}

Expand Down
82 changes: 82 additions & 0 deletions server/internal/usecase/interactor/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"io"
"time"

"github.com/reearth/reearth-cms/server/internal/usecase"
Expand All @@ -25,6 +26,9 @@ import (
"golang.org/x/exp/slices"
)

const maxPerPage = 100
const defaultPerPage int64 = 50

type Item struct {
repos *repo.Container
gateways *gateway.Container
Expand Down Expand Up @@ -1179,3 +1183,81 @@ func (i Item) getReferencedItems(ctx context.Context, fields []*item.Field) ([]i
}
return i.repos.Item.FindByIDs(ctx, ids, nil)
}

// ItemsAsCSV exports items data in content to csv file by schema package.
func (i Item) ItemsAsCSV(ctx context.Context, schemaPackage *schema.Package, page *int, perPage *int, operator *usecase.Operator) (interfaces.ExportItemsToCSVResponse, error) {
if operator.AcOperator.User == nil && operator.Integration == nil {
return interfaces.ExportItemsToCSVResponse{}, interfaces.ErrInvalidOperator
}
return Run1(ctx, operator, i.repos, Usecase().Transaction(), func(ctx context.Context) (interfaces.ExportItemsToCSVResponse, error) {

// fromPagination
paginationOffset := fromPagination(page, perPage)

items, _, err := i.repos.Item.FindBySchema(ctx, schemaPackage.Schema().ID(), nil, nil, paginationOffset)
if err != nil {
return interfaces.ExportItemsToCSVResponse{}, err
}

pr, pw := io.Pipe()
err = csvFromItems(pw, items, schemaPackage.Schema())
if err != nil {
return interfaces.ExportItemsToCSVResponse{}, err
}

return interfaces.ExportItemsToCSVResponse{
PipeReader: pr,
}, nil
})
}

// ItemsAsGeoJSON converts items to Geo JSON type given the schema package
func (i Item) ItemsAsGeoJSON(ctx context.Context, schemaPackage *schema.Package, page *int, perPage *int, operator *usecase.Operator) (interfaces.ExportItemsToGeoJSONResponse, error) {

if operator.AcOperator.User == nil && operator.Integration == nil {
return interfaces.ExportItemsToGeoJSONResponse{}, interfaces.ErrInvalidOperator
}

return Run1(ctx, operator, i.repos, Usecase().Transaction(), func(ctx context.Context) (interfaces.ExportItemsToGeoJSONResponse, error) {

// fromPagination
paginationOffset := fromPagination(page, perPage)

items, _, err := i.repos.Item.FindBySchema(ctx, schemaPackage.Schema().ID(), nil, nil, paginationOffset)
if err != nil {
return interfaces.ExportItemsToGeoJSONResponse{}, err
}

featureCollections, err := featureCollectionFromItems(items, schemaPackage.Schema())
if err != nil {
return interfaces.ExportItemsToGeoJSONResponse{}, err
}

return interfaces.ExportItemsToGeoJSONResponse{
FeatureCollections: featureCollections,
}, nil
})
}

func fromPagination(page, perPage *int) *usecasex.Pagination {
p := int64(1)
if page != nil && *page > 0 {
p = int64(*page)
}

pp := defaultPerPage
if perPage != nil {
if ppr := *perPage; 1 <= ppr {
if ppr > maxPerPage {
pp = int64(maxPerPage)
} else {
pp = int64(ppr)
}
}
}

return usecasex.OffsetPagination{
Offset: (p - 1) * pp,
Limit: pp,
}.Wrap()
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package integration
package interactor

import (
"encoding/csv"
"io"

"github.com/labstack/gommon/log"
"github.com/reearth/reearth-cms/server/pkg/integrationapi"
"github.com/reearth/reearth-cms/server/pkg/item"
"github.com/reearth/reearth-cms/server/pkg/schema"
"github.com/reearth/reearthx/i18n"
"github.com/reearth/reearthx/log"
"github.com/reearth/reearthx/rerror"
"github.com/samber/lo"
)
Expand All @@ -27,12 +27,9 @@ func csvFromItems(pw *io.PipeWriter, l item.VersionedList, s *schema.Schema) err
if !s.IsPointFieldSupported() {
return pointFieldIsNotSupportedError
}

go handleCSVGeneration(pw, l, s)

return nil
}

func handleCSVGeneration(pw *io.PipeWriter, l item.VersionedList, s *schema.Schema) {
err := generateCSV(pw, l, s)
if err != nil {
Expand All @@ -42,20 +39,16 @@ func handleCSVGeneration(pw *io.PipeWriter, l item.VersionedList, s *schema.Sche
_ = pw.Close()
}
}

func generateCSV(pw *io.PipeWriter, l item.VersionedList, s *schema.Schema) error {
w := csv.NewWriter(pw)
defer w.Flush()

headers := integrationapi.BuildCSVHeaders(s)
if err := w.Write(headers); err != nil {
return err
}

nonGeoFields := lo.Filter(s.Fields(), func(f *schema.Field, _ int) bool {
return !f.IsGeometryField()
})

for _, ver := range l {
row, ok := integrationapi.RowFromItem(ver.Value(), nonGeoFields)
if ok {
Expand All @@ -67,4 +60,3 @@ func generateCSV(pw *io.PipeWriter, l item.VersionedList, s *schema.Schema) erro

return w.Error()
}

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package integration
package interactor

import (
"io"
Expand Down Expand Up @@ -44,13 +44,11 @@ func TestCSVFromItems(t *testing.T) {
MustBuild()
v1 := version.New()
vi1 := version.MustBeValue(v1, nil, version.NewRefs(version.Latest), util.Now(), i1)

// with geometry fields
ver1 := item.VersionedList{vi1}
_, pw := io.Pipe()
err := csvFromItems(pw, ver1, s1)
assert.Nil(t, err)

// no geometry fields
iid2 := id.NewItemID()
sid2 := id.NewSchemaID()
Expand All @@ -73,7 +71,6 @@ func TestCSVFromItems(t *testing.T) {
_, pw1 := io.Pipe()
err = csvFromItems(pw1, ver2, s2)
assert.Equal(t, expectErr2, err)

// point field is not supported
iid3 := id.NewItemID()
sid3 := id.NewSchemaID()
Expand All @@ -97,4 +94,4 @@ func TestCSVFromItems(t *testing.T) {
_, pw2 := io.Pipe()
err = csvFromItems(pw2, ver3, s3)
assert.Equal(t, expectErr3, err)
}
}
Loading

0 comments on commit 2e0c104

Please sign in to comment.