From 5797953cdfccfc365e5f249f5e56719d81259f30 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Fri, 14 Jun 2024 17:05:46 +0900 Subject: [PATCH 01/26] add point field to the field schema --- server/internal/adapter/gql/generated.go | 173 +++++++++++++++++- .../adapter/gql/gqlmodel/models_gen.go | 15 +- server/schemas/field.graphql | 16 +- 3 files changed, 196 insertions(+), 8 deletions(-) diff --git a/server/internal/adapter/gql/generated.go b/server/internal/adapter/gql/generated.go index f41d027198..445341901a 100644 --- a/server/internal/adapter/gql/generated.go +++ b/server/internal/adapter/gql/generated.go @@ -677,6 +677,10 @@ type ComplexityRoot struct { MaxLength func(childComplexity int) int } + SchemaFieldPoint struct { + DefaultValue func(childComplexity int) int + } + SchemaFieldReference struct { CorrespondingField func(childComplexity int) int CorrespondingFieldID func(childComplexity int) int @@ -3956,6 +3960,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.SchemaFieldMarkdown.MaxLength(childComplexity), true + case "SchemaFieldPoint.defaultValue": + if e.complexity.SchemaFieldPoint.DefaultValue == nil { + break + } + + return e.complexity.SchemaFieldPoint.DefaultValue(childComplexity), true + case "SchemaFieldReference.correspondingField": if e.complexity.SchemaFieldReference.CorrespondingField == nil { break @@ -4708,6 +4719,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputSchemaFieldDateInput, ec.unmarshalInputSchemaFieldGroupInput, ec.unmarshalInputSchemaFieldIntegerInput, + ec.unmarshalInputSchemaFieldPointInput, ec.unmarshalInputSchemaFieldReferenceInput, ec.unmarshalInputSchemaFieldRichTextInput, ec.unmarshalInputSchemaFieldSelectInput, @@ -5113,6 +5125,7 @@ extend type Mutation { Checkbox URL Group + Point } enum SchemaFieldTagColor { @@ -5129,7 +5142,6 @@ enum SchemaFieldTagColor { PURPLE } - type SchemaField { id: ID! modelId: ID @@ -5153,7 +5165,7 @@ type SchemaField { } union SchemaFieldTypeProperty = - SchemaFieldText + SchemaFieldText | SchemaFieldTextArea | SchemaFieldRichText | SchemaFieldMarkdown @@ -5167,6 +5179,7 @@ union SchemaFieldTypeProperty = | SchemaFieldURL | SchemaFieldCheckbox | SchemaFieldGroup + | SchemaFieldPoint type SchemaFieldText { defaultValue: Any @@ -5242,6 +5255,10 @@ type SchemaFieldGroup { groupId: ID! } +type SchemaFieldPoint { + defaultValue: Any +} + # Inputs input SchemaFieldTextInput { @@ -5308,7 +5325,7 @@ input CorrespondingFieldInput { key: String! description: String! required: Boolean! -} +} input SchemaFieldReferenceInput { modelId: ID! @@ -5324,6 +5341,10 @@ input SchemaFieldGroupInput { groupId: ID! } +input SchemaFieldPointInput { + defaultValue: Any +} + input SchemaFieldTypePropertyInput @onlyOne { text: SchemaFieldTextInput textArea: SchemaFieldTextAreaInput @@ -5339,6 +5360,7 @@ input SchemaFieldTypePropertyInput @onlyOne { reference: SchemaFieldReferenceInput url: SchemaFieldURLInput group: SchemaFieldGroupInput + point: SchemaFieldPointInput } input CreateFieldInput { @@ -26707,6 +26729,47 @@ func (ec *executionContext) fieldContext_SchemaFieldMarkdown_maxLength(ctx conte return fc, nil } +func (ec *executionContext) _SchemaFieldPoint_defaultValue(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldPoint) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SchemaFieldPoint_defaultValue(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DefaultValue, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(interface{}) + fc.Result = res + return ec.marshalOAny2interface(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_SchemaFieldPoint_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "SchemaFieldPoint", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Any does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _SchemaFieldReference_modelId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldReference) (ret graphql.Marshaler) { fc, err := ec.fieldContext_SchemaFieldReference_modelId(ctx, field) if err != nil { @@ -36041,6 +36104,33 @@ func (ec *executionContext) unmarshalInputSchemaFieldIntegerInput(ctx context.Co return it, nil } +func (ec *executionContext) unmarshalInputSchemaFieldPointInput(ctx context.Context, obj interface{}) (gqlmodel.SchemaFieldPointInput, error) { + var it gqlmodel.SchemaFieldPointInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"defaultValue"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "defaultValue": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("defaultValue")) + data, err := ec.unmarshalOAny2interface(ctx, v) + if err != nil { + return it, err + } + it.DefaultValue = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputSchemaFieldReferenceInput(ctx context.Context, obj interface{}) (gqlmodel.SchemaFieldReferenceInput, error) { var it gqlmodel.SchemaFieldReferenceInput asMap := map[string]interface{}{} @@ -36300,7 +36390,7 @@ func (ec *executionContext) unmarshalInputSchemaFieldTypePropertyInput(ctx conte asMap[k] = v } - fieldsInOrder := [...]string{"text", "textArea", "richText", "markdownText", "asset", "date", "bool", "select", "tag", "checkbox", "integer", "reference", "url", "group"} + fieldsInOrder := [...]string{"text", "textArea", "richText", "markdownText", "asset", "date", "bool", "select", "tag", "checkbox", "integer", "reference", "url", "group", "point"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -36643,6 +36733,30 @@ func (ec *executionContext) unmarshalInputSchemaFieldTypePropertyInput(ctx conte err := fmt.Errorf(`unexpected type %T from directive, should be *github.com/reearth/reearth-cms/server/internal/adapter/gql/gqlmodel.SchemaFieldGroupInput`, tmp) return it, graphql.ErrorOnPath(ctx, err) } + case "point": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("point")) + directive0 := func(ctx context.Context) (interface{}, error) { + return ec.unmarshalOSchemaFieldPointInput2ᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐSchemaFieldPointInput(ctx, v) + } + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.OnlyOne == nil { + return nil, errors.New("directive onlyOne is not implemented") + } + return ec.directives.OnlyOne(ctx, obj, directive0) + } + + tmp, err := directive1(ctx) + if err != nil { + return it, graphql.ErrorOnPath(ctx, err) + } + if data, ok := tmp.(*gqlmodel.SchemaFieldPointInput); ok { + it.Point = data + } else if tmp == nil { + it.Point = nil + } else { + err := fmt.Errorf(`unexpected type %T from directive, should be *github.com/reearth/reearth-cms/server/internal/adapter/gql/gqlmodel.SchemaFieldPointInput`, tmp) + return it, graphql.ErrorOnPath(ctx, err) + } } } @@ -38442,6 +38556,13 @@ func (ec *executionContext) _SchemaFieldTypeProperty(ctx context.Context, sel as return graphql.Null } return ec._SchemaFieldGroup(ctx, sel, obj) + case gqlmodel.SchemaFieldPoint: + return ec._SchemaFieldPoint(ctx, sel, &obj) + case *gqlmodel.SchemaFieldPoint: + if obj == nil { + return graphql.Null + } + return ec._SchemaFieldPoint(ctx, sel, obj) default: panic(fmt.Errorf("unexpected type %T", obj)) } @@ -44233,6 +44354,42 @@ func (ec *executionContext) _SchemaFieldMarkdown(ctx context.Context, sel ast.Se return out } +var schemaFieldPointImplementors = []string{"SchemaFieldPoint", "SchemaFieldTypeProperty"} + +func (ec *executionContext) _SchemaFieldPoint(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.SchemaFieldPoint) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, schemaFieldPointImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("SchemaFieldPoint") + case "defaultValue": + out.Values[i] = ec._SchemaFieldPoint_defaultValue(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var schemaFieldReferenceImplementors = []string{"SchemaFieldReference", "SchemaFieldTypeProperty"} func (ec *executionContext) _SchemaFieldReference(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.SchemaFieldReference) graphql.Marshaler { @@ -50285,6 +50442,14 @@ func (ec *executionContext) unmarshalOSchemaFieldIntegerInput2ᚖgithubᚗcomᚋ return &res, graphql.ErrorOnPath(ctx, err) } +func (ec *executionContext) unmarshalOSchemaFieldPointInput2ᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐSchemaFieldPointInput(ctx context.Context, v interface{}) (*gqlmodel.SchemaFieldPointInput, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputSchemaFieldPointInput(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalOSchemaFieldReferenceInput2ᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐSchemaFieldReferenceInput(ctx context.Context, v interface{}) (*gqlmodel.SchemaFieldReferenceInput, error) { if v == nil { return nil, nil diff --git a/server/internal/adapter/gql/gqlmodel/models_gen.go b/server/internal/adapter/gql/gqlmodel/models_gen.go index af4dd24ee3..d4424648fc 100644 --- a/server/internal/adapter/gql/gqlmodel/models_gen.go +++ b/server/internal/adapter/gql/gqlmodel/models_gen.go @@ -1000,6 +1000,16 @@ type SchemaFieldMarkdown struct { func (SchemaFieldMarkdown) IsSchemaFieldTypeProperty() {} +type SchemaFieldPoint struct { + DefaultValue interface{} `json:"defaultValue,omitempty"` +} + +func (SchemaFieldPoint) IsSchemaFieldTypeProperty() {} + +type SchemaFieldPointInput struct { + DefaultValue interface{} `json:"defaultValue,omitempty"` +} + type SchemaFieldReference struct { ModelID ID `json:"modelId"` SchemaID ID `json:"schemaId"` @@ -1103,6 +1113,7 @@ type SchemaFieldTypePropertyInput struct { Reference *SchemaFieldReferenceInput `json:"reference,omitempty"` URL *SchemaFieldURLInput `json:"url,omitempty"` Group *SchemaFieldGroupInput `json:"group,omitempty"` + Point *SchemaFieldPointInput `json:"point,omitempty"` } type SchemaFieldURL struct { @@ -2306,6 +2317,7 @@ const ( SchemaFieldTypeCheckbox SchemaFieldType = "Checkbox" SchemaFieldTypeURL SchemaFieldType = "URL" SchemaFieldTypeGroup SchemaFieldType = "Group" + SchemaFieldTypePoint SchemaFieldType = "Point" ) var AllSchemaFieldType = []SchemaFieldType{ @@ -2323,11 +2335,12 @@ var AllSchemaFieldType = []SchemaFieldType{ SchemaFieldTypeCheckbox, SchemaFieldTypeURL, SchemaFieldTypeGroup, + SchemaFieldTypePoint, } func (e SchemaFieldType) IsValid() bool { switch e { - case SchemaFieldTypeText, SchemaFieldTypeTextArea, SchemaFieldTypeRichText, SchemaFieldTypeMarkdownText, SchemaFieldTypeAsset, SchemaFieldTypeDate, SchemaFieldTypeBool, SchemaFieldTypeSelect, SchemaFieldTypeTag, SchemaFieldTypeInteger, SchemaFieldTypeReference, SchemaFieldTypeCheckbox, SchemaFieldTypeURL, SchemaFieldTypeGroup: + case SchemaFieldTypeText, SchemaFieldTypeTextArea, SchemaFieldTypeRichText, SchemaFieldTypeMarkdownText, SchemaFieldTypeAsset, SchemaFieldTypeDate, SchemaFieldTypeBool, SchemaFieldTypeSelect, SchemaFieldTypeTag, SchemaFieldTypeInteger, SchemaFieldTypeReference, SchemaFieldTypeCheckbox, SchemaFieldTypeURL, SchemaFieldTypeGroup, SchemaFieldTypePoint: return true } return false diff --git a/server/schemas/field.graphql b/server/schemas/field.graphql index a5eca1822c..630d30d779 100644 --- a/server/schemas/field.graphql +++ b/server/schemas/field.graphql @@ -13,6 +13,7 @@ enum SchemaFieldType { Checkbox URL Group + Point } enum SchemaFieldTagColor { @@ -29,7 +30,6 @@ enum SchemaFieldTagColor { PURPLE } - type SchemaField { id: ID! modelId: ID @@ -53,7 +53,7 @@ type SchemaField { } union SchemaFieldTypeProperty = - SchemaFieldText + SchemaFieldText | SchemaFieldTextArea | SchemaFieldRichText | SchemaFieldMarkdown @@ -67,6 +67,7 @@ union SchemaFieldTypeProperty = | SchemaFieldURL | SchemaFieldCheckbox | SchemaFieldGroup + | SchemaFieldPoint type SchemaFieldText { defaultValue: Any @@ -142,6 +143,10 @@ type SchemaFieldGroup { groupId: ID! } +type SchemaFieldPoint { + defaultValue: Any +} + # Inputs input SchemaFieldTextInput { @@ -208,7 +213,7 @@ input CorrespondingFieldInput { key: String! description: String! required: Boolean! -} +} input SchemaFieldReferenceInput { modelId: ID! @@ -224,6 +229,10 @@ input SchemaFieldGroupInput { groupId: ID! } +input SchemaFieldPointInput { + defaultValue: Any +} + input SchemaFieldTypePropertyInput @onlyOne { text: SchemaFieldTextInput textArea: SchemaFieldTextAreaInput @@ -239,6 +248,7 @@ input SchemaFieldTypePropertyInput @onlyOne { reference: SchemaFieldReferenceInput url: SchemaFieldURLInput group: SchemaFieldGroupInput + point: SchemaFieldPointInput } input CreateFieldInput { From 5043f928db995505a8e86f5283c48283bf2c1692 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Fri, 14 Jun 2024 17:08:58 +0900 Subject: [PATCH 02/26] add point to convert schema --- .../adapter/gql/gqlmodel/convert_schema.go | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/server/internal/adapter/gql/gqlmodel/convert_schema.go b/server/internal/adapter/gql/gqlmodel/convert_schema.go index 5e2e84762f..87cb82cc21 100644 --- a/server/internal/adapter/gql/gqlmodel/convert_schema.go +++ b/server/internal/adapter/gql/gqlmodel/convert_schema.go @@ -234,6 +234,19 @@ func ToSchemaFieldTypeProperty(tp *schema.TypeProperty, dv *value.Multiple, mult DefaultValue: v, } }, + Point: func(f *schema.FieldPoint) { + var v any = nil + if dv != nil { + if multiple { + v, _ = dv.ValuesPosition() + } else { + v, _ = dv.First().ValuePosition() + } + } + res = &SchemaFieldPoint{ + DefaultValue: v, + } + }, }) return } @@ -490,6 +503,17 @@ func FromSchemaTypeProperty(tp *SchemaFieldTypePropertyInput, t SchemaFieldType, dv = FromValue(SchemaFieldTypeURL, x.DefaultValue).AsMultiple() } tpRes = schema.NewURL().TypeProperty() + case SchemaFieldTypePoint: + x := tp.Point + if x == nil { + return nil, nil, ErrInvalidTypeProperty + } + if multiple { + dv = value.NewMultiple(value.TypePoint, unpackArray(x.DefaultValue)) + } else { + dv = FromValue(SchemaFieldTypePoint, x.DefaultValue).AsMultiple() + } + tpRes = schema.NewPoint().TypeProperty() default: return nil, nil, ErrInvalidTypeProperty } From 7279afad6a08380eaa40ec8a94496880755415a5 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Fri, 14 Jun 2024 17:09:16 +0900 Subject: [PATCH 03/26] add field point to schema domain models --- server/pkg/schema/field_point.go | 41 +++++++++++++++++++++++++++++ server/pkg/schema/field_position.go | 41 +++++++++++++++++++++++++++++ server/pkg/schema/type_property.go | 19 +++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 server/pkg/schema/field_point.go create mode 100644 server/pkg/schema/field_position.go diff --git a/server/pkg/schema/field_point.go b/server/pkg/schema/field_point.go new file mode 100644 index 0000000000..d8f8767f41 --- /dev/null +++ b/server/pkg/schema/field_point.go @@ -0,0 +1,41 @@ +package schema + +import "github.com/reearth/reearth-cms/server/pkg/value" + +type FieldPoint struct { + p *FieldPosition +} + +func NewPoint() *FieldPoint { + return &FieldPoint{ + p: NewPosition(value.TypePoint), + } +} + +func (f *FieldPoint) TypeProperty() *TypeProperty { + return &TypeProperty{ + t: f.Type(), + point: f, + } +} + +func (f *FieldPoint) Type() value.Type { + return value.TypePoint +} + +func (f *FieldPoint) Clone() *FieldPoint { + if f == nil { + return nil + } + return &FieldPoint{ + p: f.p.Clone(), + } +} + +func (f *FieldPoint) Validate(v *value.Value) error { + return f.p.Validate(v) +} + +func (f *FieldPoint) ValidateMultiple(v *value.Multiple) error { + return nil +} diff --git a/server/pkg/schema/field_position.go b/server/pkg/schema/field_position.go new file mode 100644 index 0000000000..83b7b2ca14 --- /dev/null +++ b/server/pkg/schema/field_position.go @@ -0,0 +1,41 @@ +package schema + +import ( + "github.com/reearth/reearth-cms/server/pkg/value" +) + +type FieldPosition struct { + t value.Type +} + +func NewPosition(t value.Type) *FieldPosition { + return &FieldPosition{ + t: t, + } +} + +func (f *FieldPosition) Type() value.Type { + return f.t +} + +func (f *FieldPosition) Clone() *FieldPosition { + if f == nil { + return nil + } + return &FieldPosition{ + t: f.t, + } +} + +func (f *FieldPosition) Validate(v *value.Value) error { + if v.Type() != f.t { + return ErrInvalidValue + } + + _, ok := v.ValuePosition() + if !ok { + return ErrInvalidValue + } + + return nil +} diff --git a/server/pkg/schema/type_property.go b/server/pkg/schema/type_property.go index bd3d8fb59a..32181ebd7f 100644 --- a/server/pkg/schema/type_property.go +++ b/server/pkg/schema/type_property.go @@ -27,6 +27,7 @@ type TypeProperty struct { reference *FieldReference url *FieldURL group *FieldGroup + point *FieldPoint } type TypePropertyMatch struct { @@ -45,6 +46,7 @@ type TypePropertyMatch struct { Reference func(*FieldReference) URL func(*FieldURL) Group func(*FieldGroup) + Point func(*FieldPoint) Default func() } @@ -64,6 +66,7 @@ type TypePropertyMatch1[T any] struct { Reference func(*FieldReference) T URL func(*FieldURL) T Group func(*FieldGroup) T + Point func(*FieldPoint) T Default func() T } @@ -118,6 +121,9 @@ func (t *TypeProperty) Validate(v *value.Value) error { Group: func(f *FieldGroup) error { return f.Validate(v) }, + Point: func(f *FieldPoint) error { + return f.Validate(v) + }, }) } @@ -165,6 +171,9 @@ func (t *TypeProperty) ValidateMultiple(v *value.Multiple) error { Group: func(f *FieldGroup) error { return f.ValidateMultiple(v) }, + Point: func(f *FieldPoint) error { + return f.ValidateMultiple(v) + }, }) } @@ -252,6 +261,11 @@ func (t *TypeProperty) Match(m TypePropertyMatch) { m.URL(t.url) return } + case value.TypePoint: + if m.Point != nil { + m.Point(t.point) + return + } } if m.Default != nil { @@ -281,6 +295,7 @@ func (t *TypeProperty) Clone() *TypeProperty { reference: t.reference.Clone(), group: t.group.Clone(), url: t.url.Clone(), + point: t.point.Clone(), } } @@ -353,6 +368,10 @@ func MatchTypeProperty1[T any](t *TypeProperty, m TypePropertyMatch1[T]) (res T) if m.Group != nil { return m.Group(t.group) } + case value.TypePoint: + if m.Point != nil { + return m.Point(t.point) + } } if m.Default != nil { From 0572fda6ea66e51f4f1ee2bb6d7e8aaf37f82df6 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Fri, 14 Jun 2024 18:01:32 +0900 Subject: [PATCH 04/26] add unit tests --- .../gql/gqlmodel/convert_schema_test.go | 13 +++++++ server/pkg/schema/field_point_test.go | 35 +++++++++++++++++++ server/pkg/schema/field_position.go | 4 +-- server/pkg/schema/field_position_test.go | 27 ++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 server/pkg/schema/field_point_test.go create mode 100644 server/pkg/schema/field_position_test.go diff --git a/server/internal/adapter/gql/gqlmodel/convert_schema_test.go b/server/internal/adapter/gql/gqlmodel/convert_schema_test.go index b9dcc74814..d279c16066 100644 --- a/server/internal/adapter/gql/gqlmodel/convert_schema_test.go +++ b/server/internal/adapter/gql/gqlmodel/convert_schema_test.go @@ -209,6 +209,11 @@ func TestToSchemaFieldTypeProperty(t *testing.T) { args: args{tp: schema.NewSelect([]string{"v1"}).TypeProperty()}, want: &SchemaFieldSelect{Values: []string{"v1"}, DefaultValue: nil}, }, + { + name: "point", + args: args{tp: schema.NewPoint().TypeProperty()}, + want: &SchemaFieldPoint{DefaultValue: nil}, + }, } for _, tt := range tests { tt := tt @@ -330,6 +335,14 @@ func TestFromSchemaFieldTypeProperty(t *testing.T) { argsT: SchemaFieldTypeSelect, wantError: ErrEmptyOptions, }, + { + name: "point", + argsInp: &SchemaFieldTypePropertyInput{ + Point: &SchemaFieldPointInput{DefaultValue: nil}, + }, + argsT: SchemaFieldTypePoint, + wantTp: schema.NewPoint().TypeProperty(), + }, { name: "tags empty", argsInp: &SchemaFieldTypePropertyInput{ diff --git a/server/pkg/schema/field_point_test.go b/server/pkg/schema/field_point_test.go new file mode 100644 index 0000000000..c72dcf892c --- /dev/null +++ b/server/pkg/schema/field_point_test.go @@ -0,0 +1,35 @@ +package schema + +import ( + "testing" + + "github.com/reearth/reearth-cms/server/pkg/value" + "github.com/stretchr/testify/assert" +) + +func TestNewPoint(t *testing.T) { + assert.Equal(t, &FieldPoint{p: &FieldPosition{t: value.TypePoint}}, NewPoint()) +} + +func TestFieldPoint_Type(t *testing.T) { + assert.Equal(t, value.TypePoint, (&FieldPoint{p: &FieldPosition{t: value.TypePoint}}).Type()) +} + +func TestFieldPoint_TypeProperty(t *testing.T) { + f := FieldPoint{} + assert.Equal(t, &TypeProperty{ + t: f.Type(), + point: &f, + }, (&f).TypeProperty()) +} + +func TestFieldPoint_Clone(t *testing.T) { + assert.Nil(t, (*FieldPoint)(nil).Clone()) + assert.Equal(t, &FieldPoint{}, (&FieldPoint{}).Clone()) +} + +func TestFieldPoint_Validate(t *testing.T) { + assert.NoError(t, (&FieldPoint{p: &FieldPosition{t: value.TypePoint}}).Validate(value.TypePoint.Value([]float64{1.12345, 2.12345}))) + assert.Equal(t, ErrInvalidValue, (&FieldPoint{p: &FieldPosition{t: value.TypePoint}}).Validate(value.TypePoint.Value([]float64{1.12345}))) + assert.Equal(t, ErrInvalidValue, (&FieldPoint{p: &FieldPosition{t: value.TypePoint}}).Validate(value.TypePoint.Value(""))) +} diff --git a/server/pkg/schema/field_position.go b/server/pkg/schema/field_position.go index 83b7b2ca14..b6b4ff1e89 100644 --- a/server/pkg/schema/field_position.go +++ b/server/pkg/schema/field_position.go @@ -32,8 +32,8 @@ func (f *FieldPosition) Validate(v *value.Value) error { return ErrInvalidValue } - _, ok := v.ValuePosition() - if !ok { + vp, ok := v.ValuePosition() + if !ok || len(vp) < 2 { return ErrInvalidValue } diff --git a/server/pkg/schema/field_position_test.go b/server/pkg/schema/field_position_test.go new file mode 100644 index 0000000000..f96a3c8d29 --- /dev/null +++ b/server/pkg/schema/field_position_test.go @@ -0,0 +1,27 @@ +package schema + +import ( + "testing" + + "github.com/reearth/reearth-cms/server/pkg/value" + "github.com/stretchr/testify/assert" +) + +func TestNewPosition(t *testing.T) { + assert.Equal(t, &FieldPosition{t: value.TypePoint}, NewPosition(value.TypePoint)) +} + +func TestFieldPosition_Type(t *testing.T) { + assert.Equal(t, value.TypePoint, (&FieldPosition{t: value.TypePoint}).Type()) +} + +func TestFieldPosition_Clone(t *testing.T) { + assert.Nil(t, (*FieldPosition)(nil).Clone()) + assert.Equal(t, &FieldPosition{t: value.TypePoint}, (&FieldPosition{t: value.TypePoint}).Clone()) +} + +func TestFieldPosition_Validate(t *testing.T) { + assert.NoError(t, (&FieldPosition{t: value.TypePoint}).Validate(value.TypePoint.Value([]float64{1.12345, 2.12345}))) + assert.Equal(t, ErrInvalidValue, (&FieldPosition{t: value.TypePoint}).Validate(value.TypeNumber.Value([]float64{1.12345}))) + assert.Equal(t, ErrInvalidValue, (&FieldPosition{t: value.TypePoint}).Validate(value.TypeNumber.Value(1))) +} From b64c5bc4940982e0962abf6f25424449c81db9ad Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Tue, 18 Jun 2024 16:08:12 +0900 Subject: [PATCH 05/26] add line string to field.graphql --- server/schemas/field.graphql | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/server/schemas/field.graphql b/server/schemas/field.graphql index 630d30d779..95a654d332 100644 --- a/server/schemas/field.graphql +++ b/server/schemas/field.graphql @@ -14,6 +14,7 @@ enum SchemaFieldType { URL Group Point + LineString } enum SchemaFieldTagColor { @@ -68,6 +69,7 @@ union SchemaFieldTypeProperty = | SchemaFieldCheckbox | SchemaFieldGroup | SchemaFieldPoint + | SchemaFieldLineString type SchemaFieldText { defaultValue: Any @@ -147,6 +149,10 @@ type SchemaFieldPoint { defaultValue: Any } +type SchemaFieldLineString { + defaultValue: Any +} + # Inputs input SchemaFieldTextInput { @@ -233,6 +239,10 @@ input SchemaFieldPointInput { defaultValue: Any } +input SchemaFieldLineStringInput { + defaultValue: Any +} + input SchemaFieldTypePropertyInput @onlyOne { text: SchemaFieldTextInput textArea: SchemaFieldTextAreaInput @@ -249,6 +259,7 @@ input SchemaFieldTypePropertyInput @onlyOne { url: SchemaFieldURLInput group: SchemaFieldGroupInput point: SchemaFieldPointInput + lineString: SchemaFieldLineStringInput } input CreateFieldInput { From e2aadab485a744645d7a6c4dee1967739bae8216 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Tue, 18 Jun 2024 17:15:12 +0900 Subject: [PATCH 06/26] wip --- server/pkg/schema/field_line_string.go | 10 ++++----- server/pkg/value/line_string.go | 29 +++++++++++++------------- server/pkg/value/position.go | 2 -- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/server/pkg/schema/field_line_string.go b/server/pkg/schema/field_line_string.go index 3860f0cde0..c654c00a68 100644 --- a/server/pkg/schema/field_line_string.go +++ b/server/pkg/schema/field_line_string.go @@ -3,12 +3,12 @@ package schema import "github.com/reearth/reearth-cms/server/pkg/value" type FieldLineString struct { - p FieldLineString + t value.Type } -func NewLineString() *FieldLineString { +func NewLineString(t value.Type) *FieldLineString { return &FieldLineString{ - p: NewLineString(value.TypeLineString), + t: t, } } @@ -28,12 +28,12 @@ func (f *FieldLineString) Clone() *FieldLineString { return nil } return &FieldLineString{ - p: f.p.Clone(), + t: f.t, } } func (f *FieldLineString) Validate(v *value.Value) error { - return f.p.Validate(v) + return nil } func (f *FieldLineString) ValidateMultiple(v *value.Multiple) error { diff --git a/server/pkg/value/line_string.go b/server/pkg/value/line_string.go index e18f2e4b04..73974b94da 100644 --- a/server/pkg/value/line_string.go +++ b/server/pkg/value/line_string.go @@ -1,8 +1,6 @@ package value import ( - "slices" - "github.com/samber/lo" ) @@ -25,7 +23,7 @@ func (*propertyLineString) ToInterface(v any) (any, bool) { } func (*propertyLineString) Validate(i any) bool { - v, ok := i.(Position) + v, ok := i.(LineString) if !ok { return false } @@ -33,30 +31,31 @@ func (*propertyLineString) Validate(i any) bool { } func (*propertyLineString) Equal(v, w any) bool { - vv := v.(Position) - ww := w.(Position) - if len(vv) != len(ww) { - return false - } - return slices.Equal(vv, ww) + // vv := v.(LineString) + // ww := w.(LineString) + // if len(vv) != len(ww) { + // return false + // } + // return slices.Equal(vv, ww) + return false } func (*propertyLineString) IsEmpty(i any) bool { if i == nil { return true } - v, ok := i.(Position) + v, ok := i.(LineString) if !ok { return true } return len(v) == 0 } -func (v *Value) ValuePosition() (vv Position, ok bool) { +func (v *Value) ValueLineString() (vv LineString, ok bool) { if v == nil { return } - vv, ok = v.v.(Position) + vv, ok = v.v.(LineString) if !ok { return nil, false } @@ -66,12 +65,12 @@ func (v *Value) ValuePosition() (vv Position, ok bool) { return } -func (m *Multiple) ValuesPosition() (vv []Position, ok bool) { +func (m *Multiple) ValuesLineString() (vv []LineString, ok bool) { if m == nil { return } - vv = lo.FilterMap(m.v, func(v *Value, _ int) (Position, bool) { - return v.ValuePosition() + vv = lo.FilterMap(m.v, func(v *Value, _ int) (LineString, bool) { + return v.ValueLineString() }) if len(vv) != len(m.v) { return nil, false diff --git a/server/pkg/value/position.go b/server/pkg/value/position.go index 9a91902cd9..b2a7c12b71 100644 --- a/server/pkg/value/position.go +++ b/server/pkg/value/position.go @@ -9,8 +9,6 @@ import ( ) const TypePoint Type = "point" -// const TypeLineString Type = "lineString" -// const TypePolygon Type = "polygon" type propertyPosition struct{} From 7751f441d5448c0c3fb39995ed409f73342d8ff4 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 19 Jun 2024 12:48:02 +0900 Subject: [PATCH 07/26] wip: line string value --- server/pkg/value/line_string.go | 41 +++++++++++++++++++++++++-------- server/pkg/value/position.go | 8 +++++++ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/server/pkg/value/line_string.go b/server/pkg/value/line_string.go index 73974b94da..e7107d8a4b 100644 --- a/server/pkg/value/line_string.go +++ b/server/pkg/value/line_string.go @@ -11,10 +11,26 @@ type propertyLineString struct{} type LineString = []Position func (p *propertyLineString) ToValue(i any) (any, bool) { + return toLineStringValue(i) +} + +func toLineStringValue(i any) (LineString, bool) { if i == nil { return nil, true } + v, ok := i.([]any) + if ok { + res := make(LineString, len(v)) + for i, vv := range v { + var ok bool + res[i], ok = toPositionValue(vv) + if !ok { + return nil, false + } + } + return res, true + } return nil, false } @@ -31,13 +47,21 @@ func (*propertyLineString) Validate(i any) bool { } func (*propertyLineString) Equal(v, w any) bool { - // vv := v.(LineString) - // ww := w.(LineString) - // if len(vv) != len(ww) { - // return false - // } - // return slices.Equal(vv, ww) - return false + return lineStringEqual(v, w) +} + +func lineStringEqual(v, w any) bool { + vv := v.(LineString) + ww := w.(LineString) + if len(vv) != len(ww) { + return false + } + for i := range vv { + if !positionEqual(vv[i], ww[i]) { + return false + } + } + return true } func (*propertyLineString) IsEmpty(i any) bool { @@ -59,9 +83,6 @@ func (v *Value) ValueLineString() (vv LineString, ok bool) { if !ok { return nil, false } - if len(vv) > 3 { - return vv[:3], true // TODO: need to think about his case - } return } diff --git a/server/pkg/value/position.go b/server/pkg/value/position.go index b2a7c12b71..24074b456b 100644 --- a/server/pkg/value/position.go +++ b/server/pkg/value/position.go @@ -15,6 +15,10 @@ type propertyPosition struct{} type Position = []float64 func (p *propertyPosition) ToValue(i any) (any, bool) { + return toPositionValue(i) +} + +func toPositionValue(i any) (Position, bool) { if i == nil { return nil, true } @@ -152,6 +156,10 @@ func (*propertyPosition) Validate(i any) bool { } func (*propertyPosition) Equal(v, w any) bool { + return positionEqual(v, w) +} + +func positionEqual(v, w any) bool { vv := v.(Position) ww := w.(Position) if len(vv) != len(ww) { From f986a86908aa05e8cb4a343abe502e1ba947fc3d Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 19 Jun 2024 13:01:56 +0900 Subject: [PATCH 08/26] wip: fix toValue in position and line string --- server/pkg/value/line_string.go | 3 +++ server/pkg/value/position.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/server/pkg/value/line_string.go b/server/pkg/value/line_string.go index e7107d8a4b..121ce42bd2 100644 --- a/server/pkg/value/line_string.go +++ b/server/pkg/value/line_string.go @@ -11,6 +11,9 @@ type propertyLineString struct{} type LineString = []Position func (p *propertyLineString) ToValue(i any) (any, bool) { + if i == nil { + return nil, true + } return toLineStringValue(i) } diff --git a/server/pkg/value/position.go b/server/pkg/value/position.go index 24074b456b..bb635511db 100644 --- a/server/pkg/value/position.go +++ b/server/pkg/value/position.go @@ -15,6 +15,9 @@ type propertyPosition struct{} type Position = []float64 func (p *propertyPosition) ToValue(i any) (any, bool) { + if i == nil { + return nil, true + } return toPositionValue(i) } From b5e2d2d09ff1fd3e773f74f089df02208056da1f Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 19 Jun 2024 13:15:48 +0900 Subject: [PATCH 09/26] wip: field line string --- server/pkg/schema/field_line_string.go | 28 ++++++++-------- server/pkg/value/match.go | 46 ++++++++++++++++---------- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/server/pkg/schema/field_line_string.go b/server/pkg/schema/field_line_string.go index c654c00a68..9d950d8541 100644 --- a/server/pkg/schema/field_line_string.go +++ b/server/pkg/schema/field_line_string.go @@ -2,19 +2,15 @@ package schema import "github.com/reearth/reearth-cms/server/pkg/value" -type FieldLineString struct { - t value.Type -} +type FieldLineString struct {} -func NewLineString(t value.Type) *FieldLineString { - return &FieldLineString{ - t: t, - } +func NewLineString() *FieldLineString { + return &FieldLineString{} } func (f *FieldLineString) TypeProperty() *TypeProperty { return &TypeProperty{ - t: f.Type(), + t: f.Type(), lineString: f, } } @@ -27,13 +23,19 @@ func (f *FieldLineString) Clone() *FieldLineString { if f == nil { return nil } - return &FieldLineString{ - t: f.t, - } + return &FieldLineString{} } -func (f *FieldLineString) Validate(v *value.Value) error { - return nil +func (f *FieldLineString) Validate(v *value.Value) (err error) { + v.Match(value.Match{ + LineString: func(a value.LineString) { + // ok + }, + Default: func() { + err = ErrInvalidValue + }, + }) + return } func (f *FieldLineString) ValidateMultiple(v *value.Multiple) error { diff --git a/server/pkg/value/match.go b/server/pkg/value/match.go index 530eba2832..b93db298d3 100644 --- a/server/pkg/value/match.go +++ b/server/pkg/value/match.go @@ -1,23 +1,25 @@ package value type Match struct { - Asset func(Asset) - Bool func(Bool) - Checkbox func(Bool) - DateTime func(DateTime) - Integer func(Integer) - Number func(Number) - String func(String) - Text func(String) - TextArea func(String) - RichText func(String) - Markdown func(String) - Select func(String) - Tag func(String) - Reference func(Reference) - URL func(URL) - Group func(Group) - Default func() + Asset func(Asset) + Bool func(Bool) + Checkbox func(Bool) + DateTime func(DateTime) + Integer func(Integer) + Number func(Number) + String func(String) + Text func(String) + TextArea func(String) + RichText func(String) + Markdown func(String) + Select func(String) + Tag func(String) + Reference func(Reference) + URL func(URL) + Group func(Group) + Point func(Position) + LineString func(LineString) + Default func() } func (v *Value) Match(m Match) { @@ -103,6 +105,16 @@ func (v *Value) Match(m Match) { m.Group(v.v.(Group)) return } + case TypePoint: + if m.Point != nil { + m.Point(v.v.(Position)) + return + } + case TypeLineString: + if m.LineString != nil { + m.LineString(v.v.(LineString)) + return + } } if m.Default != nil { From 47a4902853b1756169226013145aec0505bc2f18 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 19 Jun 2024 13:29:30 +0900 Subject: [PATCH 10/26] add line-string to convert schema --- .../adapter/gql/gqlmodel/convert_schema.go | 24 +++++++++++++++++++ .../gql/gqlmodel/convert_schema_test.go | 13 ++++++++++ 2 files changed, 37 insertions(+) diff --git a/server/internal/adapter/gql/gqlmodel/convert_schema.go b/server/internal/adapter/gql/gqlmodel/convert_schema.go index 87cb82cc21..0c13e08080 100644 --- a/server/internal/adapter/gql/gqlmodel/convert_schema.go +++ b/server/internal/adapter/gql/gqlmodel/convert_schema.go @@ -247,6 +247,19 @@ func ToSchemaFieldTypeProperty(tp *schema.TypeProperty, dv *value.Multiple, mult DefaultValue: v, } }, + LineString: func(f *schema.FieldLineString) { + var v any = nil + if dv != nil { + if multiple { + v, _ = dv.ValuesLineString() + } else { + v, _ = dv.First().ValueLineString() + } + } + res = &SchemaFieldLineString{ + DefaultValue: v, + } + }, }) return } @@ -514,6 +527,17 @@ func FromSchemaTypeProperty(tp *SchemaFieldTypePropertyInput, t SchemaFieldType, dv = FromValue(SchemaFieldTypePoint, x.DefaultValue).AsMultiple() } tpRes = schema.NewPoint().TypeProperty() + case SchemaFieldTypeLineString: + x := tp.LineString + if x == nil { + return nil, nil, ErrInvalidTypeProperty + } + if multiple { + dv = value.NewMultiple(value.TypeLineString, unpackArray(x.DefaultValue)) + } else { + dv = FromValue(SchemaFieldTypeLineString, x.DefaultValue).AsMultiple() + } + tpRes = schema.NewLineString().TypeProperty() default: return nil, nil, ErrInvalidTypeProperty } diff --git a/server/internal/adapter/gql/gqlmodel/convert_schema_test.go b/server/internal/adapter/gql/gqlmodel/convert_schema_test.go index d279c16066..7e05c75bbc 100644 --- a/server/internal/adapter/gql/gqlmodel/convert_schema_test.go +++ b/server/internal/adapter/gql/gqlmodel/convert_schema_test.go @@ -214,6 +214,11 @@ func TestToSchemaFieldTypeProperty(t *testing.T) { args: args{tp: schema.NewPoint().TypeProperty()}, want: &SchemaFieldPoint{DefaultValue: nil}, }, + { + name: "line-string", + args: args{tp: schema.NewLineString().TypeProperty()}, + want: &SchemaFieldLineString{DefaultValue: nil}, + }, } for _, tt := range tests { tt := tt @@ -343,6 +348,14 @@ func TestFromSchemaFieldTypeProperty(t *testing.T) { argsT: SchemaFieldTypePoint, wantTp: schema.NewPoint().TypeProperty(), }, + { + name: "line-string", + argsInp: &SchemaFieldTypePropertyInput{ + LineString: &SchemaFieldLineStringInput{DefaultValue: nil}, + }, + argsT: SchemaFieldTypeLineString, + wantTp: schema.NewLineString().TypeProperty(), + }, { name: "tags empty", argsInp: &SchemaFieldTypePropertyInput{ From 90edd7a065d15e0e0a018cf6557667b9b82c057e Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Thu, 20 Jun 2024 11:58:36 +0900 Subject: [PATCH 11/26] update match_test --- server/pkg/value/match_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/server/pkg/value/match_test.go b/server/pkg/value/match_test.go index f37a3d8cdf..eeb6b35f92 100644 --- a/server/pkg/value/match_test.go +++ b/server/pkg/value/match_test.go @@ -50,6 +50,14 @@ func TestValue_Match(t *testing.T) { res = nil (&Value{t: TypeBool}).Match(Match{Default: func() { res = "default" }}) assert.Equal(t, "default", res) + + res = nil + (&Value{t: TypePoint}).Match(Match{Default: func() { res = "default" }}) + assert.Equal(t, "default", res) + + res = nil + (&Value{t: TypeLineString}).Match(Match{Default: func() { res = "default" }}) + assert.Equal(t, "default", res) } func TestOptional_Match(t *testing.T) { From 5792c59f502d65901cbc705191e56af653cce20c Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Thu, 20 Jun 2024 12:23:29 +0900 Subject: [PATCH 12/26] update to value --- server/pkg/value/line_string.go | 63 +++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/server/pkg/value/line_string.go b/server/pkg/value/line_string.go index 121ce42bd2..d68701a2a9 100644 --- a/server/pkg/value/line_string.go +++ b/server/pkg/value/line_string.go @@ -1,6 +1,8 @@ package value import ( + "encoding/json" + "github.com/samber/lo" ) @@ -22,19 +24,58 @@ func toLineStringValue(i any) (LineString, bool) { return nil, true } - v, ok := i.([]any) - if ok { - res := make(LineString, len(v)) - for i, vv := range v { - var ok bool - res[i], ok = toPositionValue(vv) - if !ok { - return nil, false - } + switch v := i.(type) { + case [][]float64: + return v, true + case [][]float32: + return convertToFloat64WithCheck(v, mapFloat32ToFloat64) + case [][]int: + return convertToFloat64(v, mapIntegersToFloat64) + case [][]int8: + return convertToFloat64(v, mapIntegersToFloat64) + case [][]int16: + return convertToFloat64(v, mapIntegersToFloat64) + case [][]int32: + return convertToFloat64(v, mapIntegersToFloat64) + case [][]int64: + return convertToFloat64(v, mapIntegersToFloat64) + case [][]uint: + return convertToFloat64(v, mapIntegersToFloat64) + case [][]uint8: + return convertToFloat64(v, mapIntegersToFloat64) + case [][]uint16: + return convertToFloat64(v, mapIntegersToFloat64) + case [][]uint32: + return convertToFloat64(v, mapIntegersToFloat64) + case [][]uint64: + return convertToFloat64(v, mapIntegersToFloat64) + case [][]uintptr: + return convertToFloat64(v, mapIntegersToFloat64) + case [][]json.Number: + return convertToFloat64WithCheck(v, mapJSONNumbersToFloat64) + case [][]string: + return convertToFloat64WithCheck(v, mapStringsToFloat64) + default: + return nil, false + } +} + +func convertToFloat64[T any](v [][]T, mapper func([]T) []float64) (LineString, bool) { + return lo.Map(v, func(n []T, _ int) Position { + return mapper(n) + }), true +} + +func convertToFloat64WithCheck[T any](v [][]T, mapper func([]T) ([]float64, bool)) (LineString, bool) { + res := make(LineString, len(v)) + for i, vv := range v { + var ok bool + res[i], ok = mapper(vv) + if !ok { + return nil, false } - return res, true } - return nil, false + return res, true } func (*propertyLineString) ToInterface(v any) (any, bool) { From c1fc0ac5038f579074d3694b0a84cd70d81b3304 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Thu, 20 Jun 2024 12:23:33 +0900 Subject: [PATCH 13/26] add unit test --- server/pkg/value/line_string_test.go | 180 +++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 server/pkg/value/line_string_test.go diff --git a/server/pkg/value/line_string_test.go b/server/pkg/value/line_string_test.go new file mode 100644 index 0000000000..99364b1903 --- /dev/null +++ b/server/pkg/value/line_string_test.go @@ -0,0 +1,180 @@ +package value + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_propertyLineString_ToValue(t *testing.T) { + tests := []struct { + name string + arg any + want1 any + want2 bool + }{ + { + name: "nil", + arg: nil, + want1: nil, + want2: true, + }, + { + name: "string", + arg: [][]string{{"1.1", "2.1", "3.1"}, {"1.1", "2.1", "3.1"}}, + want1: [][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, + want2: true, + }, + { + name: "json.Number", + arg: [][]json.Number{{"1.1", "2.1", "3.1"}, {"1.1", "2.1", "3.1"}}, + want1: [][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, + want2: true, + }, + { + name: "float64", + arg: [][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, + want1: [][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, + want2: true, + }, + { + name: "float32", + arg: [][]float32{{1.1234567, 2.1234567, 3.1234567}, {1.1234567, 2.1234567, 3.1234567}}, + want1: [][]float64{{1.1234567, 2.1234567, 3.1234567}, {1.1234567, 2.1234567, 3.1234567}}, + want2: true, + }, + { + name: "int", + arg: [][]int{{1, 2, 3}, {1, 2, 3}}, + want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, + want2: true, + }, + { + name: "int8", + arg: [][]int8{{1, 2, 3}, {1, 2, 3}}, + want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, + want2: true, + }, + { + name: "int16", + arg: [][]int16{{1, 2, 3}, {1, 2, 3}}, + want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, + want2: true, + }, + { + name: "int32", + arg: [][]int32{{1, 2, 3}, {1, 2, 3}}, + want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, + want2: true, + }, + { + name: "int64", + arg: [][]int64{{1, 2, 3}, {1, 2, 3}}, + want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, + want2: true, + }, + { + name: "uint", + arg: [][]uint{{1, 2, 3}, {1, 2, 3}}, + want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, + want2: true, + }, + { + name: "uint8", + arg: [][]uint8{{1, 2, 3}, {1, 2, 3}}, + want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, + want2: true, + }, + { + name: "uint16", + arg: [][]uint16{{1, 2, 3}, {1, 2, 3}}, + want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, + want2: true, + }, + { + name: "uint32", + arg: [][]uint32{{1, 2, 3}, {1, 2, 3}}, + want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, + want2: true, + }, + { + name: "uint64", + arg: [][]uint64{{1, 2, 3}, {1, 2, 3}}, + want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, + want2: true, + }, + { + name: "uintptr", + arg: [][]uintptr{{1, 2, 3}, {1, 2, 3}}, + want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, + want2: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + p := &propertyLineString{} + got1, got2 := p.ToValue(tt.arg) + assert.Equal(t, tt.want1, got1) + assert.Equal(t, tt.want2, got2) + }) + } +} + +func Test_propertyLineString_ToInterface(t *testing.T) { + v := [][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}} + tt, ok := (&propertyLineString{}).ToInterface(v) + assert.Equal(t, v, tt) + assert.Equal(t, true, ok) +} + +func Test_propertyLineString_IsEmpty(t *testing.T) { + assert.True(t, (&propertyLineString{}).IsEmpty([][]float64{})) + assert.False(t, (&propertyLineString{}).IsEmpty([][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}})) +} + +func Test_propertyLineString_Validate(t *testing.T) { + assert.True(t, (&propertyLineString{}).Validate([][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}})) + assert.False(t, (&propertyLineString{}).Validate([][]float64{{1.1}})) + assert.False(t, (&propertyLineString{}).Validate([][]int{{1, 2, 3}})) + assert.False(t, (&propertyLineString{}).Validate([][]string{{"1", "2", "3"}})) + assert.False(t, (&propertyLineString{}).Validate(1)) +} + +func Test_propertyLineString_Equal(t *testing.T) { + ps := &propertyLineString{} + assert.True(t, ps.Equal(LineString{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, LineString{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}})) + ps1 := &propertyLineString{} + assert.False(t, ps1.Equal(LineString{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, LineString{{1.1, 2.1}, {1.1, 2.1}})) +} + +func TestValue_ValueLineString(t *testing.T) { + var v *Value + got, ok := v.ValueLineString() + assert.Equal(t, [][]float64(nil), got) + assert.Equal(t, false, ok) + + v = &Value{ + v: [][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, + } + got, ok = v.ValueLineString() + assert.Equal(t, [][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, got) + assert.Equal(t, true, ok) +} + +func TestMultiple_ValuesLineString(t *testing.T) { + var m *Multiple + got, ok := m.ValuesLineString() + var expected []LineString + assert.Equal(t, expected, got) + assert.False(t, ok) + + m = NewMultiple(TypeLineString, []any{LineString{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, LineString{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, LineString{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}}) + expected = []LineString{{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, {{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, {{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}} + got, ok = m.ValuesLineString() + assert.Equal(t, expected, got) + assert.True(t, ok) +} From 03d2f9b6f8bf8f87a9bec49fd3ee1ebfff2b87b2 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Thu, 20 Jun 2024 12:34:15 +0900 Subject: [PATCH 14/26] fix: field line-string validate --- server/pkg/schema/field_line_string.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/pkg/schema/field_line_string.go b/server/pkg/schema/field_line_string.go index 9d950d8541..db4c674d06 100644 --- a/server/pkg/schema/field_line_string.go +++ b/server/pkg/schema/field_line_string.go @@ -2,7 +2,7 @@ package schema import "github.com/reearth/reearth-cms/server/pkg/value" -type FieldLineString struct {} +type FieldLineString struct{} func NewLineString() *FieldLineString { return &FieldLineString{} @@ -29,7 +29,9 @@ func (f *FieldLineString) Clone() *FieldLineString { func (f *FieldLineString) Validate(v *value.Value) (err error) { v.Match(value.Match{ LineString: func(a value.LineString) { - // ok + if len(a) < 2 { + err = ErrInvalidValue + } }, Default: func() { err = ErrInvalidValue From 17e07a564756ce31616cbb139f8081fca9dbac63 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Thu, 20 Jun 2024 12:34:29 +0900 Subject: [PATCH 15/26] add unit test for field line-string --- server/pkg/schema/field_line_string_test.go | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 server/pkg/schema/field_line_string_test.go diff --git a/server/pkg/schema/field_line_string_test.go b/server/pkg/schema/field_line_string_test.go new file mode 100644 index 0000000000..6bb71f7ab2 --- /dev/null +++ b/server/pkg/schema/field_line_string_test.go @@ -0,0 +1,36 @@ +package schema + +import ( + "testing" + + "github.com/reearth/reearth-cms/server/pkg/value" + "github.com/stretchr/testify/assert" +) + +func TestNewLineString(t *testing.T) { + assert.Equal(t, &FieldLineString{}, NewLineString()) +} + +func TestFieldLineString_Type(t *testing.T) { + assert.Equal(t, value.TypeLineString, (&FieldLineString{}).Type()) +} + +func TestFieldLineString_TypeProperty(t *testing.T) { + f := FieldLineString{} + assert.Equal(t, &TypeProperty{ + t: f.Type(), + lineString: &f, + }, (&f).TypeProperty()) +} + +func TestFieldLineString_Clone(t *testing.T) { + assert.Nil(t, (*FieldLineString)(nil).Clone()) + assert.Equal(t, &FieldLineString{}, (&FieldLineString{}).Clone()) +} + +func TestFieldLineString_Validate(t *testing.T) { + assert.NoError(t, (&FieldLineString{}).Validate(value.TypeLineString.Value([][]float64{{1.12345, 2.12345}, {1.12345, 2.12345}}))) + assert.Equal(t, ErrInvalidValue, (&FieldLineString{}).Validate(value.TypeLineString.Value([]float64{1.12345}))) + assert.Equal(t, ErrInvalidValue, (&FieldLineString{}).Validate(value.TypeLineString.Value([][]float64{{1.12345, 2.12345}}))) + assert.Equal(t, ErrInvalidValue, (&FieldLineString{}).Validate(value.TypeLineString.Value(""))) +} From 963931dac3f5cee4b8218f0a96e3df10aeeddb9a Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Thu, 20 Jun 2024 12:40:12 +0900 Subject: [PATCH 16/26] update type property test --- server/pkg/schema/type_property_test.go | 108 ++++++++++++++++++------ 1 file changed, 80 insertions(+), 28 deletions(-) diff --git a/server/pkg/schema/type_property_test.go b/server/pkg/schema/type_property_test.go index bf8cb9210b..2c46347c2e 100644 --- a/server/pkg/schema/type_property_test.go +++ b/server/pkg/schema/type_property_test.go @@ -17,20 +17,22 @@ func TestTypeProperty_Type(t *testing.T) { func TestMatchTypeProperty(t *testing.T) { val := "" m := TypePropertyMatch{ - Text: func(_ *FieldText) { val = "Text" }, - TextArea: func(_ *FieldTextArea) { val = "TextArea" }, - RichText: func(_ *FieldRichText) { val = "RichText" }, - Markdown: func(_ *FieldMarkdown) { val = "Markdown" }, - Asset: func(_ *FieldAsset) { val = "Asset" }, - DateTime: func(_ *FieldDateTime) { val = "DateTime" }, - Bool: func(_ *FieldBool) { val = "Bool" }, - Select: func(_ *FieldSelect) { val = "Select" }, - Tag: func(_ *FieldTag) { val = "Tag" }, - Integer: func(_ *FieldInteger) { val = "Integer" }, - Number: func(_ *FieldNumber) { val = "Number" }, - Reference: func(_ *FieldReference) { val = "Reference" }, - URL: func(_ *FieldURL) { val = "URL" }, - Default: func() { val = "Default" }, + Text: func(_ *FieldText) { val = "Text" }, + TextArea: func(_ *FieldTextArea) { val = "TextArea" }, + RichText: func(_ *FieldRichText) { val = "RichText" }, + Markdown: func(_ *FieldMarkdown) { val = "Markdown" }, + Asset: func(_ *FieldAsset) { val = "Asset" }, + DateTime: func(_ *FieldDateTime) { val = "DateTime" }, + Bool: func(_ *FieldBool) { val = "Bool" }, + Select: func(_ *FieldSelect) { val = "Select" }, + Tag: func(_ *FieldTag) { val = "Tag" }, + Integer: func(_ *FieldInteger) { val = "Integer" }, + Number: func(_ *FieldNumber) { val = "Number" }, + Reference: func(_ *FieldReference) { val = "Reference" }, + URL: func(_ *FieldURL) { val = "URL" }, + Point: func(_ *FieldPoint) { val = "Point" }, + LineString: func(_ *FieldLineString) { val = "LineString" }, + Default: func() { val = "Default" }, } type args struct { @@ -155,6 +157,22 @@ func TestMatchTypeProperty(t *testing.T) { }, want: "URL", }, + { + name: "Point", + args: args{ + tp: &TypeProperty{t: value.TypePoint, point: &FieldPoint{}}, + m: m, + }, + want: "Point", + }, + { + name: "LineString", + args: args{ + tp: &TypeProperty{t: value.TypeLineString, lineString: &FieldLineString{}}, + m: m, + }, + want: "LineString", + }, { name: "Default", args: args{ @@ -179,20 +197,22 @@ func TestMatchTypeProperty(t *testing.T) { func TestMatchTypeProperty1(t *testing.T) { m := TypePropertyMatch1[string]{ - Text: func(_ *FieldText) string { return "Text" }, - TextArea: func(_ *FieldTextArea) string { return "TextArea" }, - RichText: func(_ *FieldRichText) string { return "RichText" }, - Markdown: func(_ *FieldMarkdown) string { return "Markdown" }, - Asset: func(_ *FieldAsset) string { return "Asset" }, - DateTime: func(_ *FieldDateTime) string { return "DateTime" }, - Bool: func(_ *FieldBool) string { return "Bool" }, - Select: func(_ *FieldSelect) string { return "Select" }, - Tag: func(_ *FieldTag) string { return "Tag" }, - Integer: func(_ *FieldInteger) string { return "Integer" }, - Number: func(_ *FieldNumber) string { return "Number" }, - Reference: func(_ *FieldReference) string { return "Reference" }, - URL: func(_ *FieldURL) string { return "URL" }, - Default: func() string { return "Default" }, + Text: func(_ *FieldText) string { return "Text" }, + TextArea: func(_ *FieldTextArea) string { return "TextArea" }, + RichText: func(_ *FieldRichText) string { return "RichText" }, + Markdown: func(_ *FieldMarkdown) string { return "Markdown" }, + Asset: func(_ *FieldAsset) string { return "Asset" }, + DateTime: func(_ *FieldDateTime) string { return "DateTime" }, + Bool: func(_ *FieldBool) string { return "Bool" }, + Select: func(_ *FieldSelect) string { return "Select" }, + Tag: func(_ *FieldTag) string { return "Tag" }, + Integer: func(_ *FieldInteger) string { return "Integer" }, + Number: func(_ *FieldNumber) string { return "Number" }, + Reference: func(_ *FieldReference) string { return "Reference" }, + URL: func(_ *FieldURL) string { return "URL" }, + Point: func(_ *FieldPoint) string { return "Point" }, + LineString: func(_ *FieldLineString) string { return "LineString" }, + Default: func() string { return "Default" }, } type args struct { @@ -317,6 +337,22 @@ func TestMatchTypeProperty1(t *testing.T) { }, want: "URL", }, + { + name: "Point", + args: args{ + tp: &TypeProperty{t: value.TypePoint, point: &FieldPoint{}}, + m: m, + }, + want: "Point", + }, + { + name: "LineString", + args: args{ + tp: &TypeProperty{t: value.TypeLineString, lineString: &FieldLineString{}}, + m: m, + }, + want: "LineString", + }, { name: "Default", args: args{ @@ -463,6 +499,22 @@ func TestTypeProperty_Validate(t *testing.T) { }, want: nil, }, + { + name: "Point", + args: args{ + tp: &TypeProperty{t: value.TypePoint, point: NewPoint()}, + value: value.TypePoint.Value([]float64{1.1, 2.1}), + }, + want: nil, + }, + { + name: "LineString", + args: args{ + tp: &TypeProperty{t: value.TypeLineString, lineString: NewLineString()}, + value: value.TypeLineString.Value([][]float64{{1.1, 2.1}, {1.1, 2.1}}), + }, + want: nil, + }, } for _, tc := range tests { From 5ce028c7137f20966b0d161e9e565efd2572c2dc Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Tue, 25 Jun 2024 10:13:12 +0900 Subject: [PATCH 17/26] fix: toLineStringValue --- server/pkg/value/line_string.go | 38 ++++++++++++++------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/server/pkg/value/line_string.go b/server/pkg/value/line_string.go index d68701a2a9..aac9abbf22 100644 --- a/server/pkg/value/line_string.go +++ b/server/pkg/value/line_string.go @@ -28,49 +28,43 @@ func toLineStringValue(i any) (LineString, bool) { case [][]float64: return v, true case [][]float32: - return convertToFloat64WithCheck(v, mapFloat32ToFloat64) + return convertToFloat64(v) case [][]int: - return convertToFloat64(v, mapIntegersToFloat64) + return convertToFloat64(v) case [][]int8: - return convertToFloat64(v, mapIntegersToFloat64) + return convertToFloat64(v) case [][]int16: - return convertToFloat64(v, mapIntegersToFloat64) + return convertToFloat64(v) case [][]int32: - return convertToFloat64(v, mapIntegersToFloat64) + return convertToFloat64(v) case [][]int64: - return convertToFloat64(v, mapIntegersToFloat64) + return convertToFloat64(v) case [][]uint: - return convertToFloat64(v, mapIntegersToFloat64) + return convertToFloat64(v) case [][]uint8: - return convertToFloat64(v, mapIntegersToFloat64) + return convertToFloat64(v) case [][]uint16: - return convertToFloat64(v, mapIntegersToFloat64) + return convertToFloat64(v) case [][]uint32: - return convertToFloat64(v, mapIntegersToFloat64) + return convertToFloat64(v) case [][]uint64: - return convertToFloat64(v, mapIntegersToFloat64) + return convertToFloat64(v) case [][]uintptr: - return convertToFloat64(v, mapIntegersToFloat64) + return convertToFloat64(v) case [][]json.Number: - return convertToFloat64WithCheck(v, mapJSONNumbersToFloat64) + return convertToFloat64(v) case [][]string: - return convertToFloat64WithCheck(v, mapStringsToFloat64) + return convertToFloat64(v) default: return nil, false } } -func convertToFloat64[T any](v [][]T, mapper func([]T) []float64) (LineString, bool) { - return lo.Map(v, func(n []T, _ int) Position { - return mapper(n) - }), true -} - -func convertToFloat64WithCheck[T any](v [][]T, mapper func([]T) ([]float64, bool)) (LineString, bool) { +func convertToFloat64[T any](v [][]T) (LineString, bool) { res := make(LineString, len(v)) for i, vv := range v { var ok bool - res[i], ok = mapper(vv) + res[i], ok = toPositionValue(vv) if !ok { return nil, false } From eb2f795609d2b63b9ada042f4409fc2e0c99e34c Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Thu, 27 Jun 2024 13:14:57 +0900 Subject: [PATCH 18/26] revert previous code + add geometry field --- server/internal/adapter/gql/generated.go | 495 +++++++++--------- .../adapter/gql/gqlmodel/convert_schema.go | 45 +- .../gql/gqlmodel/convert_schema_test.go | 27 +- .../adapter/gql/gqlmodel/models_gen.go | 118 +++-- server/pkg/schema/field_geometry.go | 41 ++ server/pkg/schema/field_line_string.go | 45 -- server/pkg/schema/field_line_string_test.go | 36 -- server/pkg/schema/field_point.go | 41 -- server/pkg/schema/field_point_test.go | 35 -- server/pkg/schema/field_position.go | 41 -- server/pkg/schema/field_position_test.go | 27 - server/pkg/schema/type_property.go | 171 +++--- server/pkg/schema/type_property_test.go | 104 ++-- server/pkg/value/line_string.go | 138 ----- server/pkg/value/line_string_test.go | 180 ------- server/pkg/value/match.go | 48 +- server/pkg/value/match_test.go | 6 +- server/pkg/value/position.go | 210 -------- server/pkg/value/position_test.go | 180 ------- server/pkg/value/registry.go | 33 +- server/pkg/value/string.go | 1 + server/schemas/field.graphql | 29 +- 22 files changed, 565 insertions(+), 1486 deletions(-) create mode 100644 server/pkg/schema/field_geometry.go delete mode 100644 server/pkg/schema/field_line_string.go delete mode 100644 server/pkg/schema/field_line_string_test.go delete mode 100644 server/pkg/schema/field_point.go delete mode 100644 server/pkg/schema/field_point_test.go delete mode 100644 server/pkg/schema/field_position.go delete mode 100644 server/pkg/schema/field_position_test.go delete mode 100644 server/pkg/value/line_string.go delete mode 100644 server/pkg/value/line_string_test.go delete mode 100644 server/pkg/value/position.go delete mode 100644 server/pkg/value/position_test.go diff --git a/server/internal/adapter/gql/generated.go b/server/internal/adapter/gql/generated.go index 3728f98bd8..fc79300ed3 100644 --- a/server/internal/adapter/gql/generated.go +++ b/server/internal/adapter/gql/generated.go @@ -662,6 +662,11 @@ type ComplexityRoot struct { DefaultValue func(childComplexity int) int } + SchemaFieldGeometry struct { + DefaultValue func(childComplexity int) int + SupportedTypes func(childComplexity int) int + } + SchemaFieldGroup struct { GroupID func(childComplexity int) int } @@ -672,19 +677,11 @@ type ComplexityRoot struct { Min func(childComplexity int) int } - SchemaFieldLineString struct { - DefaultValue func(childComplexity int) int - } - SchemaFieldMarkdown struct { DefaultValue func(childComplexity int) int MaxLength func(childComplexity int) int } - SchemaFieldPoint struct { - DefaultValue func(childComplexity int) int - } - SchemaFieldReference struct { CorrespondingField func(childComplexity int) int CorrespondingFieldID func(childComplexity int) int @@ -3922,6 +3919,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.SchemaFieldDate.DefaultValue(childComplexity), true + case "SchemaFieldGeometry.defaultValue": + if e.complexity.SchemaFieldGeometry.DefaultValue == nil { + break + } + + return e.complexity.SchemaFieldGeometry.DefaultValue(childComplexity), true + + case "SchemaFieldGeometry.supportedTypes": + if e.complexity.SchemaFieldGeometry.SupportedTypes == nil { + break + } + + return e.complexity.SchemaFieldGeometry.SupportedTypes(childComplexity), true + case "SchemaFieldGroup.groupId": if e.complexity.SchemaFieldGroup.GroupID == nil { break @@ -3950,13 +3961,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.SchemaFieldInteger.Min(childComplexity), true - case "SchemaFieldLineString.defaultValue": - if e.complexity.SchemaFieldLineString.DefaultValue == nil { - break - } - - return e.complexity.SchemaFieldLineString.DefaultValue(childComplexity), true - case "SchemaFieldMarkdown.defaultValue": if e.complexity.SchemaFieldMarkdown.DefaultValue == nil { break @@ -3971,13 +3975,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.SchemaFieldMarkdown.MaxLength(childComplexity), true - case "SchemaFieldPoint.defaultValue": - if e.complexity.SchemaFieldPoint.DefaultValue == nil { - break - } - - return e.complexity.SchemaFieldPoint.DefaultValue(childComplexity), true - case "SchemaFieldReference.correspondingField": if e.complexity.SchemaFieldReference.CorrespondingField == nil { break @@ -4728,10 +4725,10 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputSchemaFieldBoolInput, ec.unmarshalInputSchemaFieldCheckboxInput, ec.unmarshalInputSchemaFieldDateInput, + ec.unmarshalInputSchemaFieldGeometryInput, ec.unmarshalInputSchemaFieldGroupInput, ec.unmarshalInputSchemaFieldIntegerInput, ec.unmarshalInputSchemaFieldLineStringInput, - ec.unmarshalInputSchemaFieldPointInput, ec.unmarshalInputSchemaFieldReferenceInput, ec.unmarshalInputSchemaFieldRichTextInput, ec.unmarshalInputSchemaFieldSelectInput, @@ -5137,8 +5134,7 @@ extend type Mutation { Checkbox URL Group - Point - LineString + Geometry } enum SchemaFieldTagColor { @@ -5155,6 +5151,16 @@ enum SchemaFieldTagColor { PURPLE } +enum GeometrySupportedType { + POINT + MULTIPOINT + LINESTRING + MULTILINESTRING + POLYGON + MULTIPOLYGON + GEOMETRYCOLLECTION +} + type SchemaField { id: ID! modelId: ID @@ -5192,8 +5198,7 @@ union SchemaFieldTypeProperty = | SchemaFieldURL | SchemaFieldCheckbox | SchemaFieldGroup - | SchemaFieldPoint - | SchemaFieldLineString + | SchemaFieldGeometry type SchemaFieldText { defaultValue: Any @@ -5269,12 +5274,9 @@ type SchemaFieldGroup { groupId: ID! } -type SchemaFieldPoint { - defaultValue: Any -} - -type SchemaFieldLineString { +type SchemaFieldGeometry { defaultValue: Any + supportedTypes: [GeometrySupportedType!]! } # Inputs @@ -5359,8 +5361,9 @@ input SchemaFieldGroupInput { groupId: ID! } -input SchemaFieldPointInput { +input SchemaFieldGeometryInput { defaultValue: Any + supportedTypes: [GeometrySupportedType!]! } input SchemaFieldLineStringInput { @@ -5382,8 +5385,7 @@ input SchemaFieldTypePropertyInput @onlyOne { reference: SchemaFieldReferenceInput url: SchemaFieldURLInput group: SchemaFieldGroupInput - point: SchemaFieldPointInput - lineString: SchemaFieldLineStringInput + geometry: SchemaFieldGeometryInput } input CreateFieldInput { @@ -26503,8 +26505,8 @@ func (ec *executionContext) fieldContext_SchemaFieldDate_defaultValue(ctx contex return fc, nil } -func (ec *executionContext) _SchemaFieldGroup_groupId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldGroup) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SchemaFieldGroup_groupId(ctx, field) +func (ec *executionContext) _SchemaFieldGeometry_defaultValue(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldGeometry) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SchemaFieldGeometry_defaultValue(ctx, field) if err != nil { return graphql.Null } @@ -26517,38 +26519,35 @@ func (ec *executionContext) _SchemaFieldGroup_groupId(ctx context.Context, field }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.GroupID, nil + return obj.DefaultValue, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } return graphql.Null } - res := resTmp.(gqlmodel.ID) + res := resTmp.(interface{}) fc.Result = res - return ec.marshalNID2githubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, field.Selections, res) + return ec.marshalOAny2interface(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SchemaFieldGroup_groupId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_SchemaFieldGeometry_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "SchemaFieldGroup", + Object: "SchemaFieldGeometry", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") + return nil, errors.New("field of type Any does not have child fields") }, } return fc, nil } -func (ec *executionContext) _SchemaFieldInteger_defaultValue(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldInteger) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SchemaFieldInteger_defaultValue(ctx, field) +func (ec *executionContext) _SchemaFieldGeometry_supportedTypes(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldGeometry) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SchemaFieldGeometry_supportedTypes(ctx, field) if err != nil { return graphql.Null } @@ -26561,35 +26560,38 @@ func (ec *executionContext) _SchemaFieldInteger_defaultValue(ctx context.Context }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.DefaultValue, nil + return obj.SupportedTypes, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.(interface{}) + res := resTmp.([]gqlmodel.GeometrySupportedType) fc.Result = res - return ec.marshalOAny2interface(ctx, field.Selections, res) + return ec.marshalNGeometrySupportedType2ᚕgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐGeometrySupportedTypeᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SchemaFieldInteger_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_SchemaFieldGeometry_supportedTypes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "SchemaFieldInteger", + Object: "SchemaFieldGeometry", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Any does not have child fields") + return nil, errors.New("field of type GeometrySupportedType does not have child fields") }, } return fc, nil } -func (ec *executionContext) _SchemaFieldInteger_min(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldInteger) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SchemaFieldInteger_min(ctx, field) +func (ec *executionContext) _SchemaFieldGroup_groupId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldGroup) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SchemaFieldGroup_groupId(ctx, field) if err != nil { return graphql.Null } @@ -26602,35 +26604,38 @@ func (ec *executionContext) _SchemaFieldInteger_min(ctx context.Context, field g }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Min, nil + return obj.GroupID, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.(*int) + res := resTmp.(gqlmodel.ID) fc.Result = res - return ec.marshalOInt2ᚖint(ctx, field.Selections, res) + return ec.marshalNID2githubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SchemaFieldInteger_min(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_SchemaFieldGroup_groupId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "SchemaFieldInteger", + Object: "SchemaFieldGroup", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") + return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } -func (ec *executionContext) _SchemaFieldInteger_max(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldInteger) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SchemaFieldInteger_max(ctx, field) +func (ec *executionContext) _SchemaFieldInteger_defaultValue(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldInteger) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SchemaFieldInteger_defaultValue(ctx, field) if err != nil { return graphql.Null } @@ -26643,7 +26648,7 @@ func (ec *executionContext) _SchemaFieldInteger_max(ctx context.Context, field g }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Max, nil + return obj.DefaultValue, nil }) if err != nil { ec.Error(ctx, err) @@ -26652,26 +26657,26 @@ func (ec *executionContext) _SchemaFieldInteger_max(ctx context.Context, field g if resTmp == nil { return graphql.Null } - res := resTmp.(*int) + res := resTmp.(interface{}) fc.Result = res - return ec.marshalOInt2ᚖint(ctx, field.Selections, res) + return ec.marshalOAny2interface(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SchemaFieldInteger_max(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_SchemaFieldInteger_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SchemaFieldInteger", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") + return nil, errors.New("field of type Any does not have child fields") }, } return fc, nil } -func (ec *executionContext) _SchemaFieldLineString_defaultValue(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldLineString) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SchemaFieldLineString_defaultValue(ctx, field) +func (ec *executionContext) _SchemaFieldInteger_min(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldInteger) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SchemaFieldInteger_min(ctx, field) if err != nil { return graphql.Null } @@ -26684,7 +26689,7 @@ func (ec *executionContext) _SchemaFieldLineString_defaultValue(ctx context.Cont }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.DefaultValue, nil + return obj.Min, nil }) if err != nil { ec.Error(ctx, err) @@ -26693,26 +26698,26 @@ func (ec *executionContext) _SchemaFieldLineString_defaultValue(ctx context.Cont if resTmp == nil { return graphql.Null } - res := resTmp.(interface{}) + res := resTmp.(*int) fc.Result = res - return ec.marshalOAny2interface(ctx, field.Selections, res) + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SchemaFieldLineString_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_SchemaFieldInteger_min(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "SchemaFieldLineString", + Object: "SchemaFieldInteger", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Any does not have child fields") + return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } -func (ec *executionContext) _SchemaFieldMarkdown_defaultValue(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldMarkdown) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SchemaFieldMarkdown_defaultValue(ctx, field) +func (ec *executionContext) _SchemaFieldInteger_max(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldInteger) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SchemaFieldInteger_max(ctx, field) if err != nil { return graphql.Null } @@ -26725,7 +26730,7 @@ func (ec *executionContext) _SchemaFieldMarkdown_defaultValue(ctx context.Contex }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.DefaultValue, nil + return obj.Max, nil }) if err != nil { ec.Error(ctx, err) @@ -26734,26 +26739,26 @@ func (ec *executionContext) _SchemaFieldMarkdown_defaultValue(ctx context.Contex if resTmp == nil { return graphql.Null } - res := resTmp.(interface{}) + res := resTmp.(*int) fc.Result = res - return ec.marshalOAny2interface(ctx, field.Selections, res) + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SchemaFieldMarkdown_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_SchemaFieldInteger_max(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "SchemaFieldMarkdown", + Object: "SchemaFieldInteger", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Any does not have child fields") + return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } -func (ec *executionContext) _SchemaFieldMarkdown_maxLength(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldMarkdown) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SchemaFieldMarkdown_maxLength(ctx, field) +func (ec *executionContext) _SchemaFieldMarkdown_defaultValue(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldMarkdown) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SchemaFieldMarkdown_defaultValue(ctx, field) if err != nil { return graphql.Null } @@ -26766,7 +26771,7 @@ func (ec *executionContext) _SchemaFieldMarkdown_maxLength(ctx context.Context, }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.MaxLength, nil + return obj.DefaultValue, nil }) if err != nil { ec.Error(ctx, err) @@ -26775,26 +26780,26 @@ func (ec *executionContext) _SchemaFieldMarkdown_maxLength(ctx context.Context, if resTmp == nil { return graphql.Null } - res := resTmp.(*int) + res := resTmp.(interface{}) fc.Result = res - return ec.marshalOInt2ᚖint(ctx, field.Selections, res) + return ec.marshalOAny2interface(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SchemaFieldMarkdown_maxLength(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_SchemaFieldMarkdown_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SchemaFieldMarkdown", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") + return nil, errors.New("field of type Any does not have child fields") }, } return fc, nil } -func (ec *executionContext) _SchemaFieldPoint_defaultValue(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldPoint) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SchemaFieldPoint_defaultValue(ctx, field) +func (ec *executionContext) _SchemaFieldMarkdown_maxLength(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.SchemaFieldMarkdown) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SchemaFieldMarkdown_maxLength(ctx, field) if err != nil { return graphql.Null } @@ -26807,7 +26812,7 @@ func (ec *executionContext) _SchemaFieldPoint_defaultValue(ctx context.Context, }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.DefaultValue, nil + return obj.MaxLength, nil }) if err != nil { ec.Error(ctx, err) @@ -26816,19 +26821,19 @@ func (ec *executionContext) _SchemaFieldPoint_defaultValue(ctx context.Context, if resTmp == nil { return graphql.Null } - res := resTmp.(interface{}) + res := resTmp.(*int) fc.Result = res - return ec.marshalOAny2interface(ctx, field.Selections, res) + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SchemaFieldPoint_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_SchemaFieldMarkdown_maxLength(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "SchemaFieldPoint", + Object: "SchemaFieldMarkdown", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Any does not have child fields") + return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil @@ -36100,6 +36105,40 @@ func (ec *executionContext) unmarshalInputSchemaFieldDateInput(ctx context.Conte return it, nil } +func (ec *executionContext) unmarshalInputSchemaFieldGeometryInput(ctx context.Context, obj interface{}) (gqlmodel.SchemaFieldGeometryInput, error) { + var it gqlmodel.SchemaFieldGeometryInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"defaultValue", "supportedTypes"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "defaultValue": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("defaultValue")) + data, err := ec.unmarshalOAny2interface(ctx, v) + if err != nil { + return it, err + } + it.DefaultValue = data + case "supportedTypes": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("supportedTypes")) + data, err := ec.unmarshalNGeometrySupportedType2ᚕgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐGeometrySupportedTypeᚄ(ctx, v) + if err != nil { + return it, err + } + it.SupportedTypes = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputSchemaFieldGroupInput(ctx context.Context, obj interface{}) (gqlmodel.SchemaFieldGroupInput, error) { var it gqlmodel.SchemaFieldGroupInput asMap := map[string]interface{}{} @@ -36195,33 +36234,6 @@ func (ec *executionContext) unmarshalInputSchemaFieldLineStringInput(ctx context return it, nil } -func (ec *executionContext) unmarshalInputSchemaFieldPointInput(ctx context.Context, obj interface{}) (gqlmodel.SchemaFieldPointInput, error) { - var it gqlmodel.SchemaFieldPointInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { - asMap[k] = v - } - - fieldsInOrder := [...]string{"defaultValue"} - for _, k := range fieldsInOrder { - v, ok := asMap[k] - if !ok { - continue - } - switch k { - case "defaultValue": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("defaultValue")) - data, err := ec.unmarshalOAny2interface(ctx, v) - if err != nil { - return it, err - } - it.DefaultValue = data - } - } - - return it, nil -} - func (ec *executionContext) unmarshalInputSchemaFieldReferenceInput(ctx context.Context, obj interface{}) (gqlmodel.SchemaFieldReferenceInput, error) { var it gqlmodel.SchemaFieldReferenceInput asMap := map[string]interface{}{} @@ -36481,7 +36493,7 @@ func (ec *executionContext) unmarshalInputSchemaFieldTypePropertyInput(ctx conte asMap[k] = v } - fieldsInOrder := [...]string{"text", "textArea", "richText", "markdownText", "asset", "date", "bool", "select", "tag", "checkbox", "integer", "reference", "url", "group", "point", "lineString"} + fieldsInOrder := [...]string{"text", "textArea", "richText", "markdownText", "asset", "date", "bool", "select", "tag", "checkbox", "integer", "reference", "url", "group", "geometry"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -36824,10 +36836,10 @@ func (ec *executionContext) unmarshalInputSchemaFieldTypePropertyInput(ctx conte err := fmt.Errorf(`unexpected type %T from directive, should be *github.com/reearth/reearth-cms/server/internal/adapter/gql/gqlmodel.SchemaFieldGroupInput`, tmp) return it, graphql.ErrorOnPath(ctx, err) } - case "point": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("point")) + case "geometry": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("geometry")) directive0 := func(ctx context.Context) (interface{}, error) { - return ec.unmarshalOSchemaFieldPointInput2ᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐSchemaFieldPointInput(ctx, v) + return ec.unmarshalOSchemaFieldGeometryInput2ᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐSchemaFieldGeometryInput(ctx, v) } directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OnlyOne == nil { @@ -36840,36 +36852,12 @@ func (ec *executionContext) unmarshalInputSchemaFieldTypePropertyInput(ctx conte if err != nil { return it, graphql.ErrorOnPath(ctx, err) } - if data, ok := tmp.(*gqlmodel.SchemaFieldPointInput); ok { - it.Point = data + if data, ok := tmp.(*gqlmodel.SchemaFieldGeometryInput); ok { + it.Geometry = data } else if tmp == nil { - it.Point = nil + it.Geometry = nil } else { - err := fmt.Errorf(`unexpected type %T from directive, should be *github.com/reearth/reearth-cms/server/internal/adapter/gql/gqlmodel.SchemaFieldPointInput`, tmp) - return it, graphql.ErrorOnPath(ctx, err) - } - case "lineString": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("lineString")) - directive0 := func(ctx context.Context) (interface{}, error) { - return ec.unmarshalOSchemaFieldLineStringInput2ᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐSchemaFieldLineStringInput(ctx, v) - } - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.OnlyOne == nil { - return nil, errors.New("directive onlyOne is not implemented") - } - return ec.directives.OnlyOne(ctx, obj, directive0) - } - - tmp, err := directive1(ctx) - if err != nil { - return it, graphql.ErrorOnPath(ctx, err) - } - if data, ok := tmp.(*gqlmodel.SchemaFieldLineStringInput); ok { - it.LineString = data - } else if tmp == nil { - it.LineString = nil - } else { - err := fmt.Errorf(`unexpected type %T from directive, should be *github.com/reearth/reearth-cms/server/internal/adapter/gql/gqlmodel.SchemaFieldLineStringInput`, tmp) + err := fmt.Errorf(`unexpected type %T from directive, should be *github.com/reearth/reearth-cms/server/internal/adapter/gql/gqlmodel.SchemaFieldGeometryInput`, tmp) return it, graphql.ErrorOnPath(ctx, err) } } @@ -38671,20 +38659,13 @@ func (ec *executionContext) _SchemaFieldTypeProperty(ctx context.Context, sel as return graphql.Null } return ec._SchemaFieldGroup(ctx, sel, obj) - case gqlmodel.SchemaFieldPoint: - return ec._SchemaFieldPoint(ctx, sel, &obj) - case *gqlmodel.SchemaFieldPoint: - if obj == nil { - return graphql.Null - } - return ec._SchemaFieldPoint(ctx, sel, obj) - case gqlmodel.SchemaFieldLineString: - return ec._SchemaFieldLineString(ctx, sel, &obj) - case *gqlmodel.SchemaFieldLineString: + case gqlmodel.SchemaFieldGeometry: + return ec._SchemaFieldGeometry(ctx, sel, &obj) + case *gqlmodel.SchemaFieldGeometry: if obj == nil { return graphql.Null } - return ec._SchemaFieldLineString(ctx, sel, obj) + return ec._SchemaFieldGeometry(ctx, sel, obj) default: panic(fmt.Errorf("unexpected type %T", obj)) } @@ -44359,19 +44340,21 @@ func (ec *executionContext) _SchemaFieldDate(ctx context.Context, sel ast.Select return out } -var schemaFieldGroupImplementors = []string{"SchemaFieldGroup", "SchemaFieldTypeProperty"} +var schemaFieldGeometryImplementors = []string{"SchemaFieldGeometry", "SchemaFieldTypeProperty"} -func (ec *executionContext) _SchemaFieldGroup(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.SchemaFieldGroup) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, schemaFieldGroupImplementors) +func (ec *executionContext) _SchemaFieldGeometry(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.SchemaFieldGeometry) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, schemaFieldGeometryImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("SchemaFieldGroup") - case "groupId": - out.Values[i] = ec._SchemaFieldGroup_groupId(ctx, field, obj) + out.Values[i] = graphql.MarshalString("SchemaFieldGeometry") + case "defaultValue": + out.Values[i] = ec._SchemaFieldGeometry_defaultValue(ctx, field, obj) + case "supportedTypes": + out.Values[i] = ec._SchemaFieldGeometry_supportedTypes(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -44398,23 +44381,22 @@ func (ec *executionContext) _SchemaFieldGroup(ctx context.Context, sel ast.Selec return out } -var schemaFieldIntegerImplementors = []string{"SchemaFieldInteger", "SchemaFieldTypeProperty"} +var schemaFieldGroupImplementors = []string{"SchemaFieldGroup", "SchemaFieldTypeProperty"} -func (ec *executionContext) _SchemaFieldInteger(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.SchemaFieldInteger) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, schemaFieldIntegerImplementors) +func (ec *executionContext) _SchemaFieldGroup(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.SchemaFieldGroup) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, schemaFieldGroupImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("SchemaFieldInteger") - case "defaultValue": - out.Values[i] = ec._SchemaFieldInteger_defaultValue(ctx, field, obj) - case "min": - out.Values[i] = ec._SchemaFieldInteger_min(ctx, field, obj) - case "max": - out.Values[i] = ec._SchemaFieldInteger_max(ctx, field, obj) + out.Values[i] = graphql.MarshalString("SchemaFieldGroup") + case "groupId": + out.Values[i] = ec._SchemaFieldGroup_groupId(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -44438,19 +44420,23 @@ func (ec *executionContext) _SchemaFieldInteger(ctx context.Context, sel ast.Sel return out } -var schemaFieldLineStringImplementors = []string{"SchemaFieldLineString", "SchemaFieldTypeProperty"} +var schemaFieldIntegerImplementors = []string{"SchemaFieldInteger", "SchemaFieldTypeProperty"} -func (ec *executionContext) _SchemaFieldLineString(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.SchemaFieldLineString) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, schemaFieldLineStringImplementors) +func (ec *executionContext) _SchemaFieldInteger(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.SchemaFieldInteger) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, schemaFieldIntegerImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("SchemaFieldLineString") + out.Values[i] = graphql.MarshalString("SchemaFieldInteger") case "defaultValue": - out.Values[i] = ec._SchemaFieldLineString_defaultValue(ctx, field, obj) + out.Values[i] = ec._SchemaFieldInteger_defaultValue(ctx, field, obj) + case "min": + out.Values[i] = ec._SchemaFieldInteger_min(ctx, field, obj) + case "max": + out.Values[i] = ec._SchemaFieldInteger_max(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -44512,42 +44498,6 @@ func (ec *executionContext) _SchemaFieldMarkdown(ctx context.Context, sel ast.Se return out } -var schemaFieldPointImplementors = []string{"SchemaFieldPoint", "SchemaFieldTypeProperty"} - -func (ec *executionContext) _SchemaFieldPoint(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.SchemaFieldPoint) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, schemaFieldPointImplementors) - - out := graphql.NewFieldSet(fields) - deferred := make(map[string]*graphql.FieldSet) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("SchemaFieldPoint") - case "defaultValue": - out.Values[i] = ec._SchemaFieldPoint_defaultValue(ctx, field, obj) - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.deferred, int32(len(deferred))) - - for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ - Label: label, - Path: graphql.GetPath(ctx), - FieldSet: dfs, - Context: ctx, - }) - } - - return out -} - var schemaFieldReferenceImplementors = []string{"SchemaFieldReference", "SchemaFieldTypeProperty"} func (ec *executionContext) _SchemaFieldReference(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.SchemaFieldReference) graphql.Marshaler { @@ -47192,6 +47142,77 @@ func (ec *executionContext) marshalNFloat2float64(ctx context.Context, sel ast.S return graphql.WrapContextMarshaler(ctx, res) } +func (ec *executionContext) unmarshalNGeometrySupportedType2githubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐGeometrySupportedType(ctx context.Context, v interface{}) (gqlmodel.GeometrySupportedType, error) { + var res gqlmodel.GeometrySupportedType + err := res.UnmarshalGQL(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNGeometrySupportedType2githubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐGeometrySupportedType(ctx context.Context, sel ast.SelectionSet, v gqlmodel.GeometrySupportedType) graphql.Marshaler { + return v +} + +func (ec *executionContext) unmarshalNGeometrySupportedType2ᚕgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐGeometrySupportedTypeᚄ(ctx context.Context, v interface{}) ([]gqlmodel.GeometrySupportedType, error) { + var vSlice []interface{} + if v != nil { + vSlice = graphql.CoerceList(v) + } + var err error + res := make([]gqlmodel.GeometrySupportedType, len(vSlice)) + for i := range vSlice { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) + res[i], err = ec.unmarshalNGeometrySupportedType2githubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐGeometrySupportedType(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + +func (ec *executionContext) marshalNGeometrySupportedType2ᚕgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐGeometrySupportedTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []gqlmodel.GeometrySupportedType) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNGeometrySupportedType2githubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐGeometrySupportedType(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + func (ec *executionContext) marshalNGroup2ᚕᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐGroup(ctx context.Context, sel ast.SelectionSet, v []*gqlmodel.Group) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup @@ -50584,35 +50605,27 @@ func (ec *executionContext) unmarshalOSchemaFieldDateInput2ᚖgithubᚗcomᚋree return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalOSchemaFieldGroupInput2ᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐSchemaFieldGroupInput(ctx context.Context, v interface{}) (*gqlmodel.SchemaFieldGroupInput, error) { - if v == nil { - return nil, nil - } - res, err := ec.unmarshalInputSchemaFieldGroupInput(ctx, v) - return &res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) unmarshalOSchemaFieldIntegerInput2ᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐSchemaFieldIntegerInput(ctx context.Context, v interface{}) (*gqlmodel.SchemaFieldIntegerInput, error) { +func (ec *executionContext) unmarshalOSchemaFieldGeometryInput2ᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐSchemaFieldGeometryInput(ctx context.Context, v interface{}) (*gqlmodel.SchemaFieldGeometryInput, error) { if v == nil { return nil, nil } - res, err := ec.unmarshalInputSchemaFieldIntegerInput(ctx, v) + res, err := ec.unmarshalInputSchemaFieldGeometryInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalOSchemaFieldLineStringInput2ᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐSchemaFieldLineStringInput(ctx context.Context, v interface{}) (*gqlmodel.SchemaFieldLineStringInput, error) { +func (ec *executionContext) unmarshalOSchemaFieldGroupInput2ᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐSchemaFieldGroupInput(ctx context.Context, v interface{}) (*gqlmodel.SchemaFieldGroupInput, error) { if v == nil { return nil, nil } - res, err := ec.unmarshalInputSchemaFieldLineStringInput(ctx, v) + res, err := ec.unmarshalInputSchemaFieldGroupInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalOSchemaFieldPointInput2ᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐSchemaFieldPointInput(ctx context.Context, v interface{}) (*gqlmodel.SchemaFieldPointInput, error) { +func (ec *executionContext) unmarshalOSchemaFieldIntegerInput2ᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐSchemaFieldIntegerInput(ctx context.Context, v interface{}) (*gqlmodel.SchemaFieldIntegerInput, error) { if v == nil { return nil, nil } - res, err := ec.unmarshalInputSchemaFieldPointInput(ctx, v) + res, err := ec.unmarshalInputSchemaFieldIntegerInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } diff --git a/server/internal/adapter/gql/gqlmodel/convert_schema.go b/server/internal/adapter/gql/gqlmodel/convert_schema.go index 0c13e08080..09a6856f7d 100644 --- a/server/internal/adapter/gql/gqlmodel/convert_schema.go +++ b/server/internal/adapter/gql/gqlmodel/convert_schema.go @@ -234,30 +234,18 @@ func ToSchemaFieldTypeProperty(tp *schema.TypeProperty, dv *value.Multiple, mult DefaultValue: v, } }, - Point: func(f *schema.FieldPoint) { + Geometry: func(f *schema.FieldGeometry) { var v any = nil if dv != nil { if multiple { - v, _ = dv.ValuesPosition() + v, _ = dv.ValuesString() } else { - v, _ = dv.First().ValuePosition() + v, _ = dv.First().ValueString() } } - res = &SchemaFieldPoint{ - DefaultValue: v, - } - }, - LineString: func(f *schema.FieldLineString) { - var v any = nil - if dv != nil { - if multiple { - v, _ = dv.ValuesLineString() - } else { - v, _ = dv.First().ValueLineString() - } - } - res = &SchemaFieldLineString{ - DefaultValue: v, + res = &SchemaFieldGeometry{ + DefaultValue: v, + SupportedTypes: nil, } }, }) @@ -516,28 +504,17 @@ func FromSchemaTypeProperty(tp *SchemaFieldTypePropertyInput, t SchemaFieldType, dv = FromValue(SchemaFieldTypeURL, x.DefaultValue).AsMultiple() } tpRes = schema.NewURL().TypeProperty() - case SchemaFieldTypePoint: - x := tp.Point - if x == nil { - return nil, nil, ErrInvalidTypeProperty - } - if multiple { - dv = value.NewMultiple(value.TypePoint, unpackArray(x.DefaultValue)) - } else { - dv = FromValue(SchemaFieldTypePoint, x.DefaultValue).AsMultiple() - } - tpRes = schema.NewPoint().TypeProperty() - case SchemaFieldTypeLineString: - x := tp.LineString + case SchemaFieldTypeGeometry: + x := tp.Geometry if x == nil { return nil, nil, ErrInvalidTypeProperty } if multiple { - dv = value.NewMultiple(value.TypeLineString, unpackArray(x.DefaultValue)) + dv = value.NewMultiple(value.TypeGeometry, unpackArray(x.DefaultValue)) } else { - dv = FromValue(SchemaFieldTypeLineString, x.DefaultValue).AsMultiple() + dv = FromValue(SchemaFieldTypeGeometry, x.DefaultValue).AsMultiple() } - tpRes = schema.NewLineString().TypeProperty() + tpRes = schema.NewGeometry().TypeProperty() default: return nil, nil, ErrInvalidTypeProperty } diff --git a/server/internal/adapter/gql/gqlmodel/convert_schema_test.go b/server/internal/adapter/gql/gqlmodel/convert_schema_test.go index 7e05c75bbc..b843e235ed 100644 --- a/server/internal/adapter/gql/gqlmodel/convert_schema_test.go +++ b/server/internal/adapter/gql/gqlmodel/convert_schema_test.go @@ -210,14 +210,9 @@ func TestToSchemaFieldTypeProperty(t *testing.T) { want: &SchemaFieldSelect{Values: []string{"v1"}, DefaultValue: nil}, }, { - name: "point", - args: args{tp: schema.NewPoint().TypeProperty()}, - want: &SchemaFieldPoint{DefaultValue: nil}, - }, - { - name: "line-string", - args: args{tp: schema.NewLineString().TypeProperty()}, - want: &SchemaFieldLineString{DefaultValue: nil}, + name: "geometry", + args: args{tp: schema.NewGeometry().TypeProperty()}, + want: &SchemaFieldGeometry{DefaultValue: nil}, }, } for _, tt := range tests { @@ -341,20 +336,12 @@ func TestFromSchemaFieldTypeProperty(t *testing.T) { wantError: ErrEmptyOptions, }, { - name: "point", - argsInp: &SchemaFieldTypePropertyInput{ - Point: &SchemaFieldPointInput{DefaultValue: nil}, - }, - argsT: SchemaFieldTypePoint, - wantTp: schema.NewPoint().TypeProperty(), - }, - { - name: "line-string", + name: "geometry", argsInp: &SchemaFieldTypePropertyInput{ - LineString: &SchemaFieldLineStringInput{DefaultValue: nil}, + Geometry: &SchemaFieldGeometryInput{DefaultValue: nil}, }, - argsT: SchemaFieldTypeLineString, - wantTp: schema.NewLineString().TypeProperty(), + argsT: SchemaFieldTypeGeometry, + wantTp: schema.NewGeometry().TypeProperty(), }, { name: "tags empty", diff --git a/server/internal/adapter/gql/gqlmodel/models_gen.go b/server/internal/adapter/gql/gqlmodel/models_gen.go index 8cee0045e6..16ebb0184b 100644 --- a/server/internal/adapter/gql/gqlmodel/models_gen.go +++ b/server/internal/adapter/gql/gqlmodel/models_gen.go @@ -969,6 +969,18 @@ type SchemaFieldDateInput struct { DefaultValue interface{} `json:"defaultValue,omitempty"` } +type SchemaFieldGeometry struct { + DefaultValue interface{} `json:"defaultValue,omitempty"` + SupportedTypes []GeometrySupportedType `json:"supportedTypes"` +} + +func (SchemaFieldGeometry) IsSchemaFieldTypeProperty() {} + +type SchemaFieldGeometryInput struct { + DefaultValue interface{} `json:"defaultValue,omitempty"` + SupportedTypes []GeometrySupportedType `json:"supportedTypes"` +} + type SchemaFieldGroup struct { GroupID ID `json:"groupId"` } @@ -993,12 +1005,6 @@ type SchemaFieldIntegerInput struct { Max *int `json:"max,omitempty"` } -type SchemaFieldLineString struct { - DefaultValue interface{} `json:"defaultValue,omitempty"` -} - -func (SchemaFieldLineString) IsSchemaFieldTypeProperty() {} - type SchemaFieldLineStringInput struct { DefaultValue interface{} `json:"defaultValue,omitempty"` } @@ -1010,16 +1016,6 @@ type SchemaFieldMarkdown struct { func (SchemaFieldMarkdown) IsSchemaFieldTypeProperty() {} -type SchemaFieldPoint struct { - DefaultValue interface{} `json:"defaultValue,omitempty"` -} - -func (SchemaFieldPoint) IsSchemaFieldTypeProperty() {} - -type SchemaFieldPointInput struct { - DefaultValue interface{} `json:"defaultValue,omitempty"` -} - type SchemaFieldReference struct { ModelID ID `json:"modelId"` SchemaID ID `json:"schemaId"` @@ -1109,22 +1105,21 @@ type SchemaFieldTextInput struct { } type SchemaFieldTypePropertyInput struct { - Text *SchemaFieldTextInput `json:"text,omitempty"` - TextArea *SchemaFieldTextAreaInput `json:"textArea,omitempty"` - RichText *SchemaFieldRichTextInput `json:"richText,omitempty"` - MarkdownText *SchemaMarkdownTextInput `json:"markdownText,omitempty"` - Asset *SchemaFieldAssetInput `json:"asset,omitempty"` - Date *SchemaFieldDateInput `json:"date,omitempty"` - Bool *SchemaFieldBoolInput `json:"bool,omitempty"` - Select *SchemaFieldSelectInput `json:"select,omitempty"` - Tag *SchemaFieldTagInput `json:"tag,omitempty"` - Checkbox *SchemaFieldCheckboxInput `json:"checkbox,omitempty"` - Integer *SchemaFieldIntegerInput `json:"integer,omitempty"` - Reference *SchemaFieldReferenceInput `json:"reference,omitempty"` - URL *SchemaFieldURLInput `json:"url,omitempty"` - Group *SchemaFieldGroupInput `json:"group,omitempty"` - Point *SchemaFieldPointInput `json:"point,omitempty"` - LineString *SchemaFieldLineStringInput `json:"lineString,omitempty"` + Text *SchemaFieldTextInput `json:"text,omitempty"` + TextArea *SchemaFieldTextAreaInput `json:"textArea,omitempty"` + RichText *SchemaFieldRichTextInput `json:"richText,omitempty"` + MarkdownText *SchemaMarkdownTextInput `json:"markdownText,omitempty"` + Asset *SchemaFieldAssetInput `json:"asset,omitempty"` + Date *SchemaFieldDateInput `json:"date,omitempty"` + Bool *SchemaFieldBoolInput `json:"bool,omitempty"` + Select *SchemaFieldSelectInput `json:"select,omitempty"` + Tag *SchemaFieldTagInput `json:"tag,omitempty"` + Checkbox *SchemaFieldCheckboxInput `json:"checkbox,omitempty"` + Integer *SchemaFieldIntegerInput `json:"integer,omitempty"` + Reference *SchemaFieldReferenceInput `json:"reference,omitempty"` + URL *SchemaFieldURLInput `json:"url,omitempty"` + Group *SchemaFieldGroupInput `json:"group,omitempty"` + Geometry *SchemaFieldGeometryInput `json:"geometry,omitempty"` } type SchemaFieldURL struct { @@ -1745,6 +1740,57 @@ func (e FieldType) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } +type GeometrySupportedType string + +const ( + GeometrySupportedTypePoint GeometrySupportedType = "POINT" + GeometrySupportedTypeMultipoint GeometrySupportedType = "MULTIPOINT" + GeometrySupportedTypeLinestring GeometrySupportedType = "LINESTRING" + GeometrySupportedTypeMultilinestring GeometrySupportedType = "MULTILINESTRING" + GeometrySupportedTypePolygon GeometrySupportedType = "POLYGON" + GeometrySupportedTypeMultipolygon GeometrySupportedType = "MULTIPOLYGON" + GeometrySupportedTypeGeometrycollection GeometrySupportedType = "GEOMETRYCOLLECTION" +) + +var AllGeometrySupportedType = []GeometrySupportedType{ + GeometrySupportedTypePoint, + GeometrySupportedTypeMultipoint, + GeometrySupportedTypeLinestring, + GeometrySupportedTypeMultilinestring, + GeometrySupportedTypePolygon, + GeometrySupportedTypeMultipolygon, + GeometrySupportedTypeGeometrycollection, +} + +func (e GeometrySupportedType) IsValid() bool { + switch e { + case GeometrySupportedTypePoint, GeometrySupportedTypeMultipoint, GeometrySupportedTypeLinestring, GeometrySupportedTypeMultilinestring, GeometrySupportedTypePolygon, GeometrySupportedTypeMultipolygon, GeometrySupportedTypeGeometrycollection: + return true + } + return false +} + +func (e GeometrySupportedType) String() string { + return string(e) +} + +func (e *GeometrySupportedType) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = GeometrySupportedType(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid GeometrySupportedType", str) + } + return nil +} + +func (e GeometrySupportedType) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + type IntegrationType string const ( @@ -2328,8 +2374,7 @@ const ( SchemaFieldTypeCheckbox SchemaFieldType = "Checkbox" SchemaFieldTypeURL SchemaFieldType = "URL" SchemaFieldTypeGroup SchemaFieldType = "Group" - SchemaFieldTypePoint SchemaFieldType = "Point" - SchemaFieldTypeLineString SchemaFieldType = "LineString" + SchemaFieldTypeGeometry SchemaFieldType = "Geometry" ) var AllSchemaFieldType = []SchemaFieldType{ @@ -2347,13 +2392,12 @@ var AllSchemaFieldType = []SchemaFieldType{ SchemaFieldTypeCheckbox, SchemaFieldTypeURL, SchemaFieldTypeGroup, - SchemaFieldTypePoint, - SchemaFieldTypeLineString, + SchemaFieldTypeGeometry, } func (e SchemaFieldType) IsValid() bool { switch e { - case SchemaFieldTypeText, SchemaFieldTypeTextArea, SchemaFieldTypeRichText, SchemaFieldTypeMarkdownText, SchemaFieldTypeAsset, SchemaFieldTypeDate, SchemaFieldTypeBool, SchemaFieldTypeSelect, SchemaFieldTypeTag, SchemaFieldTypeInteger, SchemaFieldTypeReference, SchemaFieldTypeCheckbox, SchemaFieldTypeURL, SchemaFieldTypeGroup, SchemaFieldTypePoint, SchemaFieldTypeLineString: + case SchemaFieldTypeText, SchemaFieldTypeTextArea, SchemaFieldTypeRichText, SchemaFieldTypeMarkdownText, SchemaFieldTypeAsset, SchemaFieldTypeDate, SchemaFieldTypeBool, SchemaFieldTypeSelect, SchemaFieldTypeTag, SchemaFieldTypeInteger, SchemaFieldTypeReference, SchemaFieldTypeCheckbox, SchemaFieldTypeURL, SchemaFieldTypeGroup, SchemaFieldTypeGeometry: return true } return false diff --git a/server/pkg/schema/field_geometry.go b/server/pkg/schema/field_geometry.go new file mode 100644 index 0000000000..54e0ad2dbf --- /dev/null +++ b/server/pkg/schema/field_geometry.go @@ -0,0 +1,41 @@ +package schema + +import "github.com/reearth/reearth-cms/server/pkg/value" + +type FieldGeometry struct { + p *FieldString +} + +func NewGeometry() *FieldGeometry { + return &FieldGeometry{ + p: NewString(value.TypeGeometry, nil), + } +} + +func (f *FieldGeometry) TypeProperty() *TypeProperty { + return &TypeProperty{ + t: f.Type(), + geometry: f, + } +} + +func (f *FieldGeometry) Type() value.Type { + return value.TypeGeometry +} + +func (f *FieldGeometry) Clone() *FieldGeometry { + if f == nil { + return nil + } + return &FieldGeometry{ + p: f.p.Clone(), + } +} + +func (f *FieldGeometry) Validate(v *value.Value) error { + return f.p.Validate(v) +} + +func (f *FieldGeometry) ValidateMultiple(v *value.Multiple) error { + return nil +} diff --git a/server/pkg/schema/field_line_string.go b/server/pkg/schema/field_line_string.go deleted file mode 100644 index db4c674d06..0000000000 --- a/server/pkg/schema/field_line_string.go +++ /dev/null @@ -1,45 +0,0 @@ -package schema - -import "github.com/reearth/reearth-cms/server/pkg/value" - -type FieldLineString struct{} - -func NewLineString() *FieldLineString { - return &FieldLineString{} -} - -func (f *FieldLineString) TypeProperty() *TypeProperty { - return &TypeProperty{ - t: f.Type(), - lineString: f, - } -} - -func (f *FieldLineString) Type() value.Type { - return value.TypeLineString -} - -func (f *FieldLineString) Clone() *FieldLineString { - if f == nil { - return nil - } - return &FieldLineString{} -} - -func (f *FieldLineString) Validate(v *value.Value) (err error) { - v.Match(value.Match{ - LineString: func(a value.LineString) { - if len(a) < 2 { - err = ErrInvalidValue - } - }, - Default: func() { - err = ErrInvalidValue - }, - }) - return -} - -func (f *FieldLineString) ValidateMultiple(v *value.Multiple) error { - return nil -} diff --git a/server/pkg/schema/field_line_string_test.go b/server/pkg/schema/field_line_string_test.go deleted file mode 100644 index 6bb71f7ab2..0000000000 --- a/server/pkg/schema/field_line_string_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package schema - -import ( - "testing" - - "github.com/reearth/reearth-cms/server/pkg/value" - "github.com/stretchr/testify/assert" -) - -func TestNewLineString(t *testing.T) { - assert.Equal(t, &FieldLineString{}, NewLineString()) -} - -func TestFieldLineString_Type(t *testing.T) { - assert.Equal(t, value.TypeLineString, (&FieldLineString{}).Type()) -} - -func TestFieldLineString_TypeProperty(t *testing.T) { - f := FieldLineString{} - assert.Equal(t, &TypeProperty{ - t: f.Type(), - lineString: &f, - }, (&f).TypeProperty()) -} - -func TestFieldLineString_Clone(t *testing.T) { - assert.Nil(t, (*FieldLineString)(nil).Clone()) - assert.Equal(t, &FieldLineString{}, (&FieldLineString{}).Clone()) -} - -func TestFieldLineString_Validate(t *testing.T) { - assert.NoError(t, (&FieldLineString{}).Validate(value.TypeLineString.Value([][]float64{{1.12345, 2.12345}, {1.12345, 2.12345}}))) - assert.Equal(t, ErrInvalidValue, (&FieldLineString{}).Validate(value.TypeLineString.Value([]float64{1.12345}))) - assert.Equal(t, ErrInvalidValue, (&FieldLineString{}).Validate(value.TypeLineString.Value([][]float64{{1.12345, 2.12345}}))) - assert.Equal(t, ErrInvalidValue, (&FieldLineString{}).Validate(value.TypeLineString.Value(""))) -} diff --git a/server/pkg/schema/field_point.go b/server/pkg/schema/field_point.go deleted file mode 100644 index d8f8767f41..0000000000 --- a/server/pkg/schema/field_point.go +++ /dev/null @@ -1,41 +0,0 @@ -package schema - -import "github.com/reearth/reearth-cms/server/pkg/value" - -type FieldPoint struct { - p *FieldPosition -} - -func NewPoint() *FieldPoint { - return &FieldPoint{ - p: NewPosition(value.TypePoint), - } -} - -func (f *FieldPoint) TypeProperty() *TypeProperty { - return &TypeProperty{ - t: f.Type(), - point: f, - } -} - -func (f *FieldPoint) Type() value.Type { - return value.TypePoint -} - -func (f *FieldPoint) Clone() *FieldPoint { - if f == nil { - return nil - } - return &FieldPoint{ - p: f.p.Clone(), - } -} - -func (f *FieldPoint) Validate(v *value.Value) error { - return f.p.Validate(v) -} - -func (f *FieldPoint) ValidateMultiple(v *value.Multiple) error { - return nil -} diff --git a/server/pkg/schema/field_point_test.go b/server/pkg/schema/field_point_test.go deleted file mode 100644 index c72dcf892c..0000000000 --- a/server/pkg/schema/field_point_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package schema - -import ( - "testing" - - "github.com/reearth/reearth-cms/server/pkg/value" - "github.com/stretchr/testify/assert" -) - -func TestNewPoint(t *testing.T) { - assert.Equal(t, &FieldPoint{p: &FieldPosition{t: value.TypePoint}}, NewPoint()) -} - -func TestFieldPoint_Type(t *testing.T) { - assert.Equal(t, value.TypePoint, (&FieldPoint{p: &FieldPosition{t: value.TypePoint}}).Type()) -} - -func TestFieldPoint_TypeProperty(t *testing.T) { - f := FieldPoint{} - assert.Equal(t, &TypeProperty{ - t: f.Type(), - point: &f, - }, (&f).TypeProperty()) -} - -func TestFieldPoint_Clone(t *testing.T) { - assert.Nil(t, (*FieldPoint)(nil).Clone()) - assert.Equal(t, &FieldPoint{}, (&FieldPoint{}).Clone()) -} - -func TestFieldPoint_Validate(t *testing.T) { - assert.NoError(t, (&FieldPoint{p: &FieldPosition{t: value.TypePoint}}).Validate(value.TypePoint.Value([]float64{1.12345, 2.12345}))) - assert.Equal(t, ErrInvalidValue, (&FieldPoint{p: &FieldPosition{t: value.TypePoint}}).Validate(value.TypePoint.Value([]float64{1.12345}))) - assert.Equal(t, ErrInvalidValue, (&FieldPoint{p: &FieldPosition{t: value.TypePoint}}).Validate(value.TypePoint.Value(""))) -} diff --git a/server/pkg/schema/field_position.go b/server/pkg/schema/field_position.go deleted file mode 100644 index b6b4ff1e89..0000000000 --- a/server/pkg/schema/field_position.go +++ /dev/null @@ -1,41 +0,0 @@ -package schema - -import ( - "github.com/reearth/reearth-cms/server/pkg/value" -) - -type FieldPosition struct { - t value.Type -} - -func NewPosition(t value.Type) *FieldPosition { - return &FieldPosition{ - t: t, - } -} - -func (f *FieldPosition) Type() value.Type { - return f.t -} - -func (f *FieldPosition) Clone() *FieldPosition { - if f == nil { - return nil - } - return &FieldPosition{ - t: f.t, - } -} - -func (f *FieldPosition) Validate(v *value.Value) error { - if v.Type() != f.t { - return ErrInvalidValue - } - - vp, ok := v.ValuePosition() - if !ok || len(vp) < 2 { - return ErrInvalidValue - } - - return nil -} diff --git a/server/pkg/schema/field_position_test.go b/server/pkg/schema/field_position_test.go deleted file mode 100644 index f96a3c8d29..0000000000 --- a/server/pkg/schema/field_position_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package schema - -import ( - "testing" - - "github.com/reearth/reearth-cms/server/pkg/value" - "github.com/stretchr/testify/assert" -) - -func TestNewPosition(t *testing.T) { - assert.Equal(t, &FieldPosition{t: value.TypePoint}, NewPosition(value.TypePoint)) -} - -func TestFieldPosition_Type(t *testing.T) { - assert.Equal(t, value.TypePoint, (&FieldPosition{t: value.TypePoint}).Type()) -} - -func TestFieldPosition_Clone(t *testing.T) { - assert.Nil(t, (*FieldPosition)(nil).Clone()) - assert.Equal(t, &FieldPosition{t: value.TypePoint}, (&FieldPosition{t: value.TypePoint}).Clone()) -} - -func TestFieldPosition_Validate(t *testing.T) { - assert.NoError(t, (&FieldPosition{t: value.TypePoint}).Validate(value.TypePoint.Value([]float64{1.12345, 2.12345}))) - assert.Equal(t, ErrInvalidValue, (&FieldPosition{t: value.TypePoint}).Validate(value.TypeNumber.Value([]float64{1.12345}))) - assert.Equal(t, ErrInvalidValue, (&FieldPosition{t: value.TypePoint}).Validate(value.TypeNumber.Value(1))) -} diff --git a/server/pkg/schema/type_property.go b/server/pkg/schema/type_property.go index 48b51f90f5..86a9803509 100644 --- a/server/pkg/schema/type_property.go +++ b/server/pkg/schema/type_property.go @@ -11,66 +11,63 @@ var ErrInvalidValue = rerror.NewE(i18n.T("invalid value")) // TypeProperty Represent special attributes for some field // only one of the type properties should be not nil type TypeProperty struct { - t value.Type - asset *FieldAsset - text *FieldText - textArea *FieldTextArea - richText *FieldRichText - markdown *FieldMarkdown - dateTime *FieldDateTime - bool *FieldBool - checkbox *FieldCheckbox - selectt *FieldSelect - tag *FieldTag - integer *FieldInteger - number *FieldNumber - reference *FieldReference - url *FieldURL - group *FieldGroup - point *FieldPoint - lineString *FieldLineString + t value.Type + asset *FieldAsset + text *FieldText + textArea *FieldTextArea + richText *FieldRichText + markdown *FieldMarkdown + dateTime *FieldDateTime + bool *FieldBool + checkbox *FieldCheckbox + selectt *FieldSelect + tag *FieldTag + integer *FieldInteger + number *FieldNumber + reference *FieldReference + url *FieldURL + group *FieldGroup + geometry *FieldGeometry } type TypePropertyMatch struct { - Text func(*FieldText) - TextArea func(*FieldTextArea) - RichText func(text *FieldRichText) - Markdown func(*FieldMarkdown) - Asset func(*FieldAsset) - DateTime func(*FieldDateTime) - Bool func(*FieldBool) - Checkbox func(checkbox *FieldCheckbox) - Select func(*FieldSelect) - Tag func(*FieldTag) - Integer func(*FieldInteger) - Number func(*FieldNumber) - Reference func(*FieldReference) - URL func(*FieldURL) - Group func(*FieldGroup) - Point func(*FieldPoint) - LineString func(*FieldLineString) - Default func() + Text func(*FieldText) + TextArea func(*FieldTextArea) + RichText func(text *FieldRichText) + Markdown func(*FieldMarkdown) + Asset func(*FieldAsset) + DateTime func(*FieldDateTime) + Bool func(*FieldBool) + Checkbox func(checkbox *FieldCheckbox) + Select func(*FieldSelect) + Tag func(*FieldTag) + Integer func(*FieldInteger) + Number func(*FieldNumber) + Reference func(*FieldReference) + URL func(*FieldURL) + Group func(*FieldGroup) + Geometry func(*FieldGeometry) + Default func() } type TypePropertyMatch1[T any] struct { - Text func(*FieldText) T - TextArea func(*FieldTextArea) T - RichText func(text *FieldRichText) T - Markdown func(*FieldMarkdown) T - Asset func(*FieldAsset) T - DateTime func(*FieldDateTime) T - Bool func(*FieldBool) T - Checkbox func(checkbox *FieldCheckbox) T - Select func(*FieldSelect) T - Tag func(*FieldTag) T - Integer func(*FieldInteger) T - Number func(*FieldNumber) T - Reference func(*FieldReference) T - URL func(*FieldURL) T - Group func(*FieldGroup) T - Point func(*FieldPoint) T - LineString func(*FieldLineString) T - Default func() T + Text func(*FieldText) T + TextArea func(*FieldTextArea) T + RichText func(text *FieldRichText) T + Markdown func(*FieldMarkdown) T + Asset func(*FieldAsset) T + DateTime func(*FieldDateTime) T + Bool func(*FieldBool) T + Checkbox func(checkbox *FieldCheckbox) T + Select func(*FieldSelect) T + Tag func(*FieldTag) T + Integer func(*FieldInteger) T + Number func(*FieldNumber) T + Reference func(*FieldReference) T + URL func(*FieldURL) T + Group func(*FieldGroup) T + Geometry func(*FieldGeometry) T + Default func() T } func (t *TypeProperty) Type() value.Type { @@ -124,10 +121,7 @@ func (t *TypeProperty) Validate(v *value.Value) error { Group: func(f *FieldGroup) error { return f.Validate(v) }, - Point: func(f *FieldPoint) error { - return f.Validate(v) - }, - LineString: func(f *FieldLineString) error { + Geometry: func(f *FieldGeometry) error { return f.Validate(v) }, }) @@ -177,10 +171,7 @@ func (t *TypeProperty) ValidateMultiple(v *value.Multiple) error { Group: func(f *FieldGroup) error { return f.ValidateMultiple(v) }, - Point: func(f *FieldPoint) error { - return f.ValidateMultiple(v) - }, - LineString: func(f *FieldLineString) error { + Geometry: func(f *FieldGeometry) error { return f.ValidateMultiple(v) }, }) @@ -270,14 +261,9 @@ func (t *TypeProperty) Match(m TypePropertyMatch) { m.URL(t.url) return } - case value.TypePoint: - if m.Point != nil { - m.Point(t.point) - return - } - case value.TypeLineString: - if m.LineString != nil { - m.LineString(t.lineString) + case value.TypeGeometry: + if m.Geometry != nil { + m.Geometry(t.geometry) return } } @@ -293,24 +279,23 @@ func (t *TypeProperty) Clone() *TypeProperty { } return &TypeProperty{ - t: t.t, - text: t.text.Clone(), - textArea: t.textArea.Clone(), - richText: t.richText.Clone(), - markdown: t.markdown.Clone(), - asset: t.asset.Clone(), - dateTime: t.dateTime.Clone(), - bool: t.bool.Clone(), - checkbox: t.checkbox.Clone(), - selectt: t.selectt.Clone(), - number: t.number.Clone(), - tag: t.tag.Clone(), - integer: t.integer.Clone(), - reference: t.reference.Clone(), - group: t.group.Clone(), - url: t.url.Clone(), - point: t.point.Clone(), - lineString: t.lineString.Clone(), + t: t.t, + text: t.text.Clone(), + textArea: t.textArea.Clone(), + richText: t.richText.Clone(), + markdown: t.markdown.Clone(), + asset: t.asset.Clone(), + dateTime: t.dateTime.Clone(), + bool: t.bool.Clone(), + checkbox: t.checkbox.Clone(), + selectt: t.selectt.Clone(), + number: t.number.Clone(), + tag: t.tag.Clone(), + integer: t.integer.Clone(), + reference: t.reference.Clone(), + group: t.group.Clone(), + url: t.url.Clone(), + geometry: t.geometry.Clone(), } } @@ -383,13 +368,9 @@ func MatchTypeProperty1[T any](t *TypeProperty, m TypePropertyMatch1[T]) (res T) if m.Group != nil { return m.Group(t.group) } - case value.TypePoint: - if m.Point != nil { - return m.Point(t.point) - } - case value.TypeLineString: - if m.LineString != nil { - return m.LineString(t.lineString) + case value.TypeGeometry: + if m.Geometry != nil { + return m.Geometry(t.geometry) } } diff --git a/server/pkg/schema/type_property_test.go b/server/pkg/schema/type_property_test.go index 2c46347c2e..57b97267e6 100644 --- a/server/pkg/schema/type_property_test.go +++ b/server/pkg/schema/type_property_test.go @@ -17,22 +17,21 @@ func TestTypeProperty_Type(t *testing.T) { func TestMatchTypeProperty(t *testing.T) { val := "" m := TypePropertyMatch{ - Text: func(_ *FieldText) { val = "Text" }, - TextArea: func(_ *FieldTextArea) { val = "TextArea" }, - RichText: func(_ *FieldRichText) { val = "RichText" }, - Markdown: func(_ *FieldMarkdown) { val = "Markdown" }, - Asset: func(_ *FieldAsset) { val = "Asset" }, - DateTime: func(_ *FieldDateTime) { val = "DateTime" }, - Bool: func(_ *FieldBool) { val = "Bool" }, - Select: func(_ *FieldSelect) { val = "Select" }, - Tag: func(_ *FieldTag) { val = "Tag" }, - Integer: func(_ *FieldInteger) { val = "Integer" }, - Number: func(_ *FieldNumber) { val = "Number" }, - Reference: func(_ *FieldReference) { val = "Reference" }, - URL: func(_ *FieldURL) { val = "URL" }, - Point: func(_ *FieldPoint) { val = "Point" }, - LineString: func(_ *FieldLineString) { val = "LineString" }, - Default: func() { val = "Default" }, + Text: func(_ *FieldText) { val = "Text" }, + TextArea: func(_ *FieldTextArea) { val = "TextArea" }, + RichText: func(_ *FieldRichText) { val = "RichText" }, + Markdown: func(_ *FieldMarkdown) { val = "Markdown" }, + Asset: func(_ *FieldAsset) { val = "Asset" }, + DateTime: func(_ *FieldDateTime) { val = "DateTime" }, + Bool: func(_ *FieldBool) { val = "Bool" }, + Select: func(_ *FieldSelect) { val = "Select" }, + Tag: func(_ *FieldTag) { val = "Tag" }, + Integer: func(_ *FieldInteger) { val = "Integer" }, + Number: func(_ *FieldNumber) { val = "Number" }, + Reference: func(_ *FieldReference) { val = "Reference" }, + URL: func(_ *FieldURL) { val = "URL" }, + Geometry: func(_ *FieldGeometry) { val = "Geometry" }, + Default: func() { val = "Default" }, } type args struct { @@ -158,20 +157,12 @@ func TestMatchTypeProperty(t *testing.T) { want: "URL", }, { - name: "Point", + name: "Geometry", args: args{ - tp: &TypeProperty{t: value.TypePoint, point: &FieldPoint{}}, + tp: &TypeProperty{t: value.TypeGeometry, geometry: &FieldGeometry{}}, m: m, }, - want: "Point", - }, - { - name: "LineString", - args: args{ - tp: &TypeProperty{t: value.TypeLineString, lineString: &FieldLineString{}}, - m: m, - }, - want: "LineString", + want: "Geometry", }, { name: "Default", @@ -197,22 +188,21 @@ func TestMatchTypeProperty(t *testing.T) { func TestMatchTypeProperty1(t *testing.T) { m := TypePropertyMatch1[string]{ - Text: func(_ *FieldText) string { return "Text" }, - TextArea: func(_ *FieldTextArea) string { return "TextArea" }, - RichText: func(_ *FieldRichText) string { return "RichText" }, - Markdown: func(_ *FieldMarkdown) string { return "Markdown" }, - Asset: func(_ *FieldAsset) string { return "Asset" }, - DateTime: func(_ *FieldDateTime) string { return "DateTime" }, - Bool: func(_ *FieldBool) string { return "Bool" }, - Select: func(_ *FieldSelect) string { return "Select" }, - Tag: func(_ *FieldTag) string { return "Tag" }, - Integer: func(_ *FieldInteger) string { return "Integer" }, - Number: func(_ *FieldNumber) string { return "Number" }, - Reference: func(_ *FieldReference) string { return "Reference" }, - URL: func(_ *FieldURL) string { return "URL" }, - Point: func(_ *FieldPoint) string { return "Point" }, - LineString: func(_ *FieldLineString) string { return "LineString" }, - Default: func() string { return "Default" }, + Text: func(_ *FieldText) string { return "Text" }, + TextArea: func(_ *FieldTextArea) string { return "TextArea" }, + RichText: func(_ *FieldRichText) string { return "RichText" }, + Markdown: func(_ *FieldMarkdown) string { return "Markdown" }, + Asset: func(_ *FieldAsset) string { return "Asset" }, + DateTime: func(_ *FieldDateTime) string { return "DateTime" }, + Bool: func(_ *FieldBool) string { return "Bool" }, + Select: func(_ *FieldSelect) string { return "Select" }, + Tag: func(_ *FieldTag) string { return "Tag" }, + Integer: func(_ *FieldInteger) string { return "Integer" }, + Number: func(_ *FieldNumber) string { return "Number" }, + Reference: func(_ *FieldReference) string { return "Reference" }, + URL: func(_ *FieldURL) string { return "URL" }, + Geometry: func(_ *FieldGeometry) string { return "Geometry" }, + Default: func() string { return "Default" }, } type args struct { @@ -338,20 +328,12 @@ func TestMatchTypeProperty1(t *testing.T) { want: "URL", }, { - name: "Point", + name: "Geometry", args: args{ - tp: &TypeProperty{t: value.TypePoint, point: &FieldPoint{}}, + tp: &TypeProperty{t: value.TypeGeometry, geometry: &FieldGeometry{}}, m: m, }, - want: "Point", - }, - { - name: "LineString", - args: args{ - tp: &TypeProperty{t: value.TypeLineString, lineString: &FieldLineString{}}, - m: m, - }, - want: "LineString", + want: "Geometry", }, { name: "Default", @@ -500,18 +482,10 @@ func TestTypeProperty_Validate(t *testing.T) { want: nil, }, { - name: "Point", - args: args{ - tp: &TypeProperty{t: value.TypePoint, point: NewPoint()}, - value: value.TypePoint.Value([]float64{1.1, 2.1}), - }, - want: nil, - }, - { - name: "LineString", + name: "Geometry", args: args{ - tp: &TypeProperty{t: value.TypeLineString, lineString: NewLineString()}, - value: value.TypeLineString.Value([][]float64{{1.1, 2.1}, {1.1, 2.1}}), + tp: &TypeProperty{t: value.TypeGeometry, geometry: NewGeometry()}, + value: value.TypeGeometry.Value("{}"), }, want: nil, }, diff --git a/server/pkg/value/line_string.go b/server/pkg/value/line_string.go deleted file mode 100644 index aac9abbf22..0000000000 --- a/server/pkg/value/line_string.go +++ /dev/null @@ -1,138 +0,0 @@ -package value - -import ( - "encoding/json" - - "github.com/samber/lo" -) - -const TypeLineString Type = "lineString" - -type propertyLineString struct{} - -type LineString = []Position - -func (p *propertyLineString) ToValue(i any) (any, bool) { - if i == nil { - return nil, true - } - return toLineStringValue(i) -} - -func toLineStringValue(i any) (LineString, bool) { - if i == nil { - return nil, true - } - - switch v := i.(type) { - case [][]float64: - return v, true - case [][]float32: - return convertToFloat64(v) - case [][]int: - return convertToFloat64(v) - case [][]int8: - return convertToFloat64(v) - case [][]int16: - return convertToFloat64(v) - case [][]int32: - return convertToFloat64(v) - case [][]int64: - return convertToFloat64(v) - case [][]uint: - return convertToFloat64(v) - case [][]uint8: - return convertToFloat64(v) - case [][]uint16: - return convertToFloat64(v) - case [][]uint32: - return convertToFloat64(v) - case [][]uint64: - return convertToFloat64(v) - case [][]uintptr: - return convertToFloat64(v) - case [][]json.Number: - return convertToFloat64(v) - case [][]string: - return convertToFloat64(v) - default: - return nil, false - } -} - -func convertToFloat64[T any](v [][]T) (LineString, bool) { - res := make(LineString, len(v)) - for i, vv := range v { - var ok bool - res[i], ok = toPositionValue(vv) - if !ok { - return nil, false - } - } - return res, true -} - -func (*propertyLineString) ToInterface(v any) (any, bool) { - return v, true -} - -func (*propertyLineString) Validate(i any) bool { - v, ok := i.(LineString) - if !ok { - return false - } - return len(v) >= 2 -} - -func (*propertyLineString) Equal(v, w any) bool { - return lineStringEqual(v, w) -} - -func lineStringEqual(v, w any) bool { - vv := v.(LineString) - ww := w.(LineString) - if len(vv) != len(ww) { - return false - } - for i := range vv { - if !positionEqual(vv[i], ww[i]) { - return false - } - } - return true -} - -func (*propertyLineString) IsEmpty(i any) bool { - if i == nil { - return true - } - v, ok := i.(LineString) - if !ok { - return true - } - return len(v) == 0 -} - -func (v *Value) ValueLineString() (vv LineString, ok bool) { - if v == nil { - return - } - vv, ok = v.v.(LineString) - if !ok { - return nil, false - } - return -} - -func (m *Multiple) ValuesLineString() (vv []LineString, ok bool) { - if m == nil { - return - } - vv = lo.FilterMap(m.v, func(v *Value, _ int) (LineString, bool) { - return v.ValueLineString() - }) - if len(vv) != len(m.v) { - return nil, false - } - return vv, true -} diff --git a/server/pkg/value/line_string_test.go b/server/pkg/value/line_string_test.go deleted file mode 100644 index 99364b1903..0000000000 --- a/server/pkg/value/line_string_test.go +++ /dev/null @@ -1,180 +0,0 @@ -package value - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_propertyLineString_ToValue(t *testing.T) { - tests := []struct { - name string - arg any - want1 any - want2 bool - }{ - { - name: "nil", - arg: nil, - want1: nil, - want2: true, - }, - { - name: "string", - arg: [][]string{{"1.1", "2.1", "3.1"}, {"1.1", "2.1", "3.1"}}, - want1: [][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, - want2: true, - }, - { - name: "json.Number", - arg: [][]json.Number{{"1.1", "2.1", "3.1"}, {"1.1", "2.1", "3.1"}}, - want1: [][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, - want2: true, - }, - { - name: "float64", - arg: [][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, - want1: [][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, - want2: true, - }, - { - name: "float32", - arg: [][]float32{{1.1234567, 2.1234567, 3.1234567}, {1.1234567, 2.1234567, 3.1234567}}, - want1: [][]float64{{1.1234567, 2.1234567, 3.1234567}, {1.1234567, 2.1234567, 3.1234567}}, - want2: true, - }, - { - name: "int", - arg: [][]int{{1, 2, 3}, {1, 2, 3}}, - want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, - want2: true, - }, - { - name: "int8", - arg: [][]int8{{1, 2, 3}, {1, 2, 3}}, - want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, - want2: true, - }, - { - name: "int16", - arg: [][]int16{{1, 2, 3}, {1, 2, 3}}, - want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, - want2: true, - }, - { - name: "int32", - arg: [][]int32{{1, 2, 3}, {1, 2, 3}}, - want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, - want2: true, - }, - { - name: "int64", - arg: [][]int64{{1, 2, 3}, {1, 2, 3}}, - want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, - want2: true, - }, - { - name: "uint", - arg: [][]uint{{1, 2, 3}, {1, 2, 3}}, - want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, - want2: true, - }, - { - name: "uint8", - arg: [][]uint8{{1, 2, 3}, {1, 2, 3}}, - want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, - want2: true, - }, - { - name: "uint16", - arg: [][]uint16{{1, 2, 3}, {1, 2, 3}}, - want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, - want2: true, - }, - { - name: "uint32", - arg: [][]uint32{{1, 2, 3}, {1, 2, 3}}, - want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, - want2: true, - }, - { - name: "uint64", - arg: [][]uint64{{1, 2, 3}, {1, 2, 3}}, - want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, - want2: true, - }, - { - name: "uintptr", - arg: [][]uintptr{{1, 2, 3}, {1, 2, 3}}, - want1: [][]float64{{1.0, 2.0, 3.0}, {1.0, 2.0, 3.0}}, - want2: true, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - p := &propertyLineString{} - got1, got2 := p.ToValue(tt.arg) - assert.Equal(t, tt.want1, got1) - assert.Equal(t, tt.want2, got2) - }) - } -} - -func Test_propertyLineString_ToInterface(t *testing.T) { - v := [][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}} - tt, ok := (&propertyLineString{}).ToInterface(v) - assert.Equal(t, v, tt) - assert.Equal(t, true, ok) -} - -func Test_propertyLineString_IsEmpty(t *testing.T) { - assert.True(t, (&propertyLineString{}).IsEmpty([][]float64{})) - assert.False(t, (&propertyLineString{}).IsEmpty([][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}})) -} - -func Test_propertyLineString_Validate(t *testing.T) { - assert.True(t, (&propertyLineString{}).Validate([][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}})) - assert.False(t, (&propertyLineString{}).Validate([][]float64{{1.1}})) - assert.False(t, (&propertyLineString{}).Validate([][]int{{1, 2, 3}})) - assert.False(t, (&propertyLineString{}).Validate([][]string{{"1", "2", "3"}})) - assert.False(t, (&propertyLineString{}).Validate(1)) -} - -func Test_propertyLineString_Equal(t *testing.T) { - ps := &propertyLineString{} - assert.True(t, ps.Equal(LineString{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, LineString{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}})) - ps1 := &propertyLineString{} - assert.False(t, ps1.Equal(LineString{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, LineString{{1.1, 2.1}, {1.1, 2.1}})) -} - -func TestValue_ValueLineString(t *testing.T) { - var v *Value - got, ok := v.ValueLineString() - assert.Equal(t, [][]float64(nil), got) - assert.Equal(t, false, ok) - - v = &Value{ - v: [][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, - } - got, ok = v.ValueLineString() - assert.Equal(t, [][]float64{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, got) - assert.Equal(t, true, ok) -} - -func TestMultiple_ValuesLineString(t *testing.T) { - var m *Multiple - got, ok := m.ValuesLineString() - var expected []LineString - assert.Equal(t, expected, got) - assert.False(t, ok) - - m = NewMultiple(TypeLineString, []any{LineString{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, LineString{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, LineString{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}}) - expected = []LineString{{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, {{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}, {{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}}} - got, ok = m.ValuesLineString() - assert.Equal(t, expected, got) - assert.True(t, ok) -} diff --git a/server/pkg/value/match.go b/server/pkg/value/match.go index b93db298d3..aebf639842 100644 --- a/server/pkg/value/match.go +++ b/server/pkg/value/match.go @@ -1,25 +1,24 @@ package value type Match struct { - Asset func(Asset) - Bool func(Bool) - Checkbox func(Bool) - DateTime func(DateTime) - Integer func(Integer) - Number func(Number) - String func(String) - Text func(String) - TextArea func(String) - RichText func(String) - Markdown func(String) - Select func(String) - Tag func(String) - Reference func(Reference) - URL func(URL) - Group func(Group) - Point func(Position) - LineString func(LineString) - Default func() + Asset func(Asset) + Bool func(Bool) + Checkbox func(Bool) + DateTime func(DateTime) + Integer func(Integer) + Number func(Number) + String func(String) + Text func(String) + TextArea func(String) + RichText func(String) + Markdown func(String) + Select func(String) + Tag func(String) + Reference func(Reference) + URL func(URL) + Group func(Group) + Geometry func(String) + Default func() } func (v *Value) Match(m Match) { @@ -105,14 +104,9 @@ func (v *Value) Match(m Match) { m.Group(v.v.(Group)) return } - case TypePoint: - if m.Point != nil { - m.Point(v.v.(Position)) - return - } - case TypeLineString: - if m.LineString != nil { - m.LineString(v.v.(LineString)) + case TypeGeometry: + if m.Geometry != nil { + m.Geometry(v.v.(String)) return } } diff --git a/server/pkg/value/match_test.go b/server/pkg/value/match_test.go index eeb6b35f92..1dab00e1fa 100644 --- a/server/pkg/value/match_test.go +++ b/server/pkg/value/match_test.go @@ -52,11 +52,7 @@ func TestValue_Match(t *testing.T) { assert.Equal(t, "default", res) res = nil - (&Value{t: TypePoint}).Match(Match{Default: func() { res = "default" }}) - assert.Equal(t, "default", res) - - res = nil - (&Value{t: TypeLineString}).Match(Match{Default: func() { res = "default" }}) + (&Value{t: TypeGeometry}).Match(Match{Default: func() { res = "default" }}) assert.Equal(t, "default", res) } diff --git a/server/pkg/value/position.go b/server/pkg/value/position.go deleted file mode 100644 index bb635511db..0000000000 --- a/server/pkg/value/position.go +++ /dev/null @@ -1,210 +0,0 @@ -package value - -import ( - "encoding/json" - "slices" - "strconv" - - "github.com/samber/lo" -) - -const TypePoint Type = "point" - -type propertyPosition struct{} - -type Position = []float64 - -func (p *propertyPosition) ToValue(i any) (any, bool) { - if i == nil { - return nil, true - } - return toPositionValue(i) -} - -func toPositionValue(i any) (Position, bool) { - if i == nil { - return nil, true - } - - switch v := i.(type) { - case []float64: - return v, true - case []float32: - return mapFloat32ToFloat64(v) - case []int: - return mapIntegersToFloat64(v), true - case []int8: - return mapIntegersToFloat64(v), true - case []int16: - return mapIntegersToFloat64(v), true - case []int32: - return mapIntegersToFloat64(v), true - case []int64: - return mapIntegersToFloat64(v), true - case []uint: - return mapIntegersToFloat64(v), true - case []uint8: - return mapIntegersToFloat64(v), true - case []uint16: - return mapIntegersToFloat64(v), true - case []uint32: - return mapIntegersToFloat64(v), true - case []uint64: - return mapIntegersToFloat64(v), true - case []uintptr: - return mapIntegersToFloat64(v), true - case []json.Number: - return mapJSONNumbersToFloat64(v) - case []string: - return mapStringsToFloat64(v) - default: - return nil, false - } -} - -func mapIntegersToFloat64[T any](v []T) []float64 { - return lo.Map(v, func(n T, _ int) float64 { - return intToFloat64(n) - }) -} - -func intToFloat64(v any) float64 { - switch val := v.(type) { - case int: - return float64(val) - case int8: - return float64(val) - case int16: - return float64(val) - case int32: - return float64(val) - case int64: - return float64(val) - case uint: - return float64(val) - case uint8: - return float64(val) - case uint16: - return float64(val) - case uint32: - return float64(val) - case uint64: - return float64(val) - case uintptr: - return float64(val) - default: - return 0 - } -} - -func mapStringsToFloat64(v []string) ([]float64, bool) { - var err error - s := lo.Map(v, func(s string, _ int) float64 { - vv, err2 := strconv.ParseFloat(s, 64) - if err2 != nil { - err = err2 - return 0 - } - return vv - }) - if err != nil { - return nil, false - } - return s, true -} - -func mapJSONNumbersToFloat64(v []json.Number) ([]float64, bool) { - var err error - s := lo.Map(v, func(n json.Number, _ int) float64 { - vv, err2 := n.Float64() - if err2 != nil { - err = err2 - return 0 - } - return vv - }) - if err != nil { - return nil, false - } - return s, true -} - -func mapFloat32ToFloat64(v []float32) ([]float64, bool) { - var err error - s := lo.Map(v, func(n float32, _ int) float64 { - ss := strconv.FormatFloat(float64(n), 'f', -1, 32) - vv, err2 := strconv.ParseFloat(ss, 64) - if err2 != nil { - err = err2 - return 0 - } - return vv - }) - if err != nil { - return nil, false - } - return s, true -} - -func (*propertyPosition) ToInterface(v any) (any, bool) { - return v, true -} - -func (*propertyPosition) Validate(i any) bool { - v, ok := i.(Position) - if !ok { - return false - } - return len(v) >= 2 -} - -func (*propertyPosition) Equal(v, w any) bool { - return positionEqual(v, w) -} - -func positionEqual(v, w any) bool { - vv := v.(Position) - ww := w.(Position) - if len(vv) != len(ww) { - return false - } - return slices.Equal(vv, ww) -} - -func (*propertyPosition) IsEmpty(i any) bool { - if i == nil { - return true - } - v, ok := i.(Position) - if !ok { - return true - } - return len(v) == 0 -} - -func (v *Value) ValuePosition() (vv Position, ok bool) { - if v == nil { - return - } - vv, ok = v.v.(Position) - if !ok { - return nil, false - } - if len(vv) > 3 { - return vv[:3], true // TODO: need to think about his case - } - return -} - -func (m *Multiple) ValuesPosition() (vv []Position, ok bool) { - if m == nil { - return - } - vv = lo.FilterMap(m.v, func(v *Value, _ int) (Position, bool) { - return v.ValuePosition() - }) - if len(vv) != len(m.v) { - return nil, false - } - return vv, true -} diff --git a/server/pkg/value/position_test.go b/server/pkg/value/position_test.go deleted file mode 100644 index c80cb5ad73..0000000000 --- a/server/pkg/value/position_test.go +++ /dev/null @@ -1,180 +0,0 @@ -package value - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_propertyPosition_ToValue(t *testing.T) { - tests := []struct { - name string - arg any - want1 any - want2 bool - }{ - { - name: "nil", - arg: nil, - want1: nil, - want2: true, - }, - { - name: "string", - arg: []string{"1.12345", "2.12345"}, - want1: []float64{1.12345, 2.12345}, - want2: true, - }, - { - name: "json.Number", - arg: []json.Number{"1.12345", "2.12345"}, - want1: []float64{1.12345, 2.12345}, - want2: true, - }, - { - name: "float64", - arg: []float64{1.12345, 2.12345}, - want1: []float64{1.12345, 2.12345}, - want2: true, - }, - { - name: "float32", - arg: []float32{1.1234567, 2.12345}, - want1: []float64{1.1234567, 2.12345}, - want2: true, - }, - { - name: "int", - arg: []int{1, 2}, - want1: []float64{1.0, 2.0}, - want2: true, - }, - { - name: "int8", - arg: []int8{1, 2}, - want1: []float64{1.0, 2.0}, - want2: true, - }, - { - name: "int16", - arg: []int16{1, 2}, - want1: []float64{1.0, 2.0}, - want2: true, - }, - { - name: "int32", - arg: []int32{1, 2}, - want1: []float64{1.0, 2.0}, - want2: true, - }, - { - name: "int64", - arg: []int64{1, 2}, - want1: []float64{1.0, 2.0}, - want2: true, - }, - { - name: "uint", - arg: []uint{1, 2}, - want1: []float64{1.0, 2.0}, - want2: true, - }, - { - name: "uint8", - arg: []uint8{1, 2}, - want1: []float64{1.0, 2.0}, - want2: true, - }, - { - name: "uint16", - arg: []uint16{1, 2}, - want1: []float64{1.0, 2.0}, - want2: true, - }, - { - name: "uint32", - arg: []uint32{1, 2}, - want1: []float64{1.0, 2.0}, - want2: true, - }, - { - name: "uint64", - arg: []uint64{1, 2}, - want1: []float64{1.0, 2.0}, - want2: true, - }, - { - name: "uintptr", - arg: []uintptr{1, 2}, - want1: []float64{1.0, 2.0}, - want2: true, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - p := &propertyPosition{} - got1, got2 := p.ToValue(tt.arg) - assert.Equal(t, tt.want1, got1) - assert.Equal(t, tt.want2, got2) - }) - } -} - -func Test_propertyPosition_ToInterface(t *testing.T) { - v := []float64{1.1, 2.1, 3.1} - tt, ok := (&propertyPosition{}).ToInterface(v) - assert.Equal(t, v, tt) - assert.Equal(t, true, ok) -} - -func Test_propertyPosition_IsEmpty(t *testing.T) { - assert.True(t, (&propertyPosition{}).IsEmpty([]float64{})) - assert.False(t, (&propertyPosition{}).IsEmpty([]float64{1.1, 2.1, 3.1})) -} - -func Test_propertyPosition_Validate(t *testing.T) { - assert.True(t, (&propertyPosition{}).Validate([]float64{1.1, 2.1, 3.1})) - assert.False(t, (&propertyPosition{}).Validate([]float64{1.1})) - assert.False(t, (&propertyPosition{}).Validate([]int{1, 2, 3})) - assert.False(t, (&propertyPosition{}).Validate([]string{"1", "2", "3"})) - assert.False(t, (&propertyPosition{}).Validate(1)) -} - -func Test_propertyPosition_Equal(t *testing.T) { - ps := &propertyPosition{} - assert.True(t, ps.Equal(Position{1.1, 2.1, 3.1}, Position{1.1, 2.1, 3.1})) - ps1 := &propertyPosition{} - assert.False(t, ps1.Equal(Position{1.1, 2.1, 3.1}, Position{1.1, 2.1})) -} - -func TestValue_ValuePosition(t *testing.T) { - var v *Value - got, ok := v.ValuePosition() - assert.Equal(t, []float64(nil), got) - assert.Equal(t, false, ok) - - v = &Value{ - v: []float64{1.1, 2.1, 3.1}, - } - got, ok = v.ValuePosition() - assert.Equal(t, []float64{1.1, 2.1, 3.1}, got) - assert.Equal(t, true, ok) -} - -func TestMultiple_ValuesPosition(t *testing.T) { - var m *Multiple - got, ok := m.ValuesPosition() - var expected []Position - assert.Equal(t, expected, got) - assert.False(t, ok) - - m = NewMultiple(TypePoint, []any{Position{1.1, 2.1, 3.1}, Position{1.1, 2.1, 3.1}, Position{1.1, 2.1, 3.1}}) - expected = []Position{{1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}, {1.1, 2.1, 3.1}} - got, ok = m.ValuesPosition() - assert.Equal(t, expected, got) - assert.True(t, ok) -} diff --git a/server/pkg/value/registry.go b/server/pkg/value/registry.go index 312de2d499..2b21f68084 100644 --- a/server/pkg/value/registry.go +++ b/server/pkg/value/registry.go @@ -1,23 +1,22 @@ package value var defaultTypes = TypeRegistry{ - TypeAsset: &propertyAsset{}, - TypeBool: &propertyBool{}, - TypeCheckbox: &propertyBool{}, - TypeDateTime: &propertyDateTime{}, - TypeInteger: &propertyInteger{}, - TypeNumber: &propertyNumber{}, - TypeText: &propertyString{}, - TypeTextArea: &propertyString{}, - TypeRichText: &propertyString{}, - TypeMarkdown: &propertyString{}, - TypeSelect: &propertyString{}, - TypeTag: &propertyString{}, - TypeGroup: &propertyGroup{}, - TypeReference: &propertyReference{}, - TypeURL: &propertyURL{}, - TypePoint: &propertyPosition{}, - TypeLineString: &propertyLineString{}, + TypeAsset: &propertyAsset{}, + TypeBool: &propertyBool{}, + TypeCheckbox: &propertyBool{}, + TypeDateTime: &propertyDateTime{}, + TypeInteger: &propertyInteger{}, + TypeNumber: &propertyNumber{}, + TypeText: &propertyString{}, + TypeTextArea: &propertyString{}, + TypeRichText: &propertyString{}, + TypeMarkdown: &propertyString{}, + TypeSelect: &propertyString{}, + TypeTag: &propertyString{}, + TypeGroup: &propertyGroup{}, + TypeReference: &propertyReference{}, + TypeURL: &propertyURL{}, + TypeGeometry: &propertyString{}, } type TypeRegistry map[Type]TypeProperty diff --git a/server/pkg/value/string.go b/server/pkg/value/string.go index 58f3d3e4fe..da594b401f 100644 --- a/server/pkg/value/string.go +++ b/server/pkg/value/string.go @@ -14,6 +14,7 @@ const TypeRichText Type = "richText" const TypeMarkdown Type = "markdown" const TypeSelect Type = "select" const TypeTag Type = "tag" +const TypeGeometry Type = "geometry" type propertyString struct{} diff --git a/server/schemas/field.graphql b/server/schemas/field.graphql index 95a654d332..af066991fc 100644 --- a/server/schemas/field.graphql +++ b/server/schemas/field.graphql @@ -13,8 +13,7 @@ enum SchemaFieldType { Checkbox URL Group - Point - LineString + Geometry } enum SchemaFieldTagColor { @@ -31,6 +30,16 @@ enum SchemaFieldTagColor { PURPLE } +enum GeometrySupportedType { + POINT + MULTIPOINT + LINESTRING + MULTILINESTRING + POLYGON + MULTIPOLYGON + GEOMETRYCOLLECTION +} + type SchemaField { id: ID! modelId: ID @@ -68,8 +77,7 @@ union SchemaFieldTypeProperty = | SchemaFieldURL | SchemaFieldCheckbox | SchemaFieldGroup - | SchemaFieldPoint - | SchemaFieldLineString + | SchemaFieldGeometry type SchemaFieldText { defaultValue: Any @@ -145,12 +153,9 @@ type SchemaFieldGroup { groupId: ID! } -type SchemaFieldPoint { - defaultValue: Any -} - -type SchemaFieldLineString { +type SchemaFieldGeometry { defaultValue: Any + supportedTypes: [GeometrySupportedType!]! } # Inputs @@ -235,8 +240,9 @@ input SchemaFieldGroupInput { groupId: ID! } -input SchemaFieldPointInput { +input SchemaFieldGeometryInput { defaultValue: Any + supportedTypes: [GeometrySupportedType!]! } input SchemaFieldLineStringInput { @@ -258,8 +264,7 @@ input SchemaFieldTypePropertyInput @onlyOne { reference: SchemaFieldReferenceInput url: SchemaFieldURLInput group: SchemaFieldGroupInput - point: SchemaFieldPointInput - lineString: SchemaFieldLineStringInput + geometry: SchemaFieldGeometryInput } input CreateFieldInput { From 26d609dc3732fbbe1d67d43d76ac0489e79ce4d4 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Fri, 28 Jun 2024 15:31:43 +0900 Subject: [PATCH 19/26] wip: geometry field --- .../adapter/gql/gqlmodel/convert_schema.go | 6 +- server/pkg/schema/field_geometry.go | 50 ++++++++++++--- .../field_geometry_supported_type_test.go | 63 +++++++++++++++++++ .../schema/field_geometry_supported_types.go | 42 +++++++++++++ server/pkg/schema/field_geometry_test.go | 38 +++++++++++ server/pkg/schema/type_property_test.go | 2 +- 6 files changed, 188 insertions(+), 13 deletions(-) create mode 100644 server/pkg/schema/field_geometry_supported_type_test.go create mode 100644 server/pkg/schema/field_geometry_supported_types.go create mode 100644 server/pkg/schema/field_geometry_test.go diff --git a/server/internal/adapter/gql/gqlmodel/convert_schema.go b/server/internal/adapter/gql/gqlmodel/convert_schema.go index 09a6856f7d..ab82eeb517 100644 --- a/server/internal/adapter/gql/gqlmodel/convert_schema.go +++ b/server/internal/adapter/gql/gqlmodel/convert_schema.go @@ -245,7 +245,7 @@ func ToSchemaFieldTypeProperty(tp *schema.TypeProperty, dv *value.Multiple, mult } res = &SchemaFieldGeometry{ DefaultValue: v, - SupportedTypes: nil, + SupportedTypes: lo.Map(f.SupportedTypes(), func(v schema.GeometrySupportedType, _ int) GeometrySupportedType { return GeometrySupportedType(v) }), } }, }) @@ -514,7 +514,9 @@ func FromSchemaTypeProperty(tp *SchemaFieldTypePropertyInput, t SchemaFieldType, } else { dv = FromValue(SchemaFieldTypeGeometry, x.DefaultValue).AsMultiple() } - tpRes = schema.NewGeometry().TypeProperty() + tpRes = schema.NewGeometry(lo.Map(x.SupportedTypes, func(v GeometrySupportedType, _ int) schema.GeometrySupportedType { + return schema.GeometrySupportedType(v) + })).TypeProperty() default: return nil, nil, ErrInvalidTypeProperty } diff --git a/server/pkg/schema/field_geometry.go b/server/pkg/schema/field_geometry.go index 54e0ad2dbf..45044ab221 100644 --- a/server/pkg/schema/field_geometry.go +++ b/server/pkg/schema/field_geometry.go @@ -1,24 +1,33 @@ package schema -import "github.com/reearth/reearth-cms/server/pkg/value" +import ( + "github.com/reearth/reearth-cms/server/pkg/value" + "golang.org/x/exp/slices" +) + +type GeometrySupportedTypeList []GeometrySupportedType type FieldGeometry struct { - p *FieldString + st GeometrySupportedTypeList } -func NewGeometry() *FieldGeometry { +func NewGeometry(supportedTypes GeometrySupportedTypeList) *FieldGeometry { return &FieldGeometry{ - p: NewString(value.TypeGeometry, nil), + st: supportedTypes, } } func (f *FieldGeometry) TypeProperty() *TypeProperty { return &TypeProperty{ - t: f.Type(), + t: f.Type(), geometry: f, } } +func (f *FieldGeometry) SupportedTypes() GeometrySupportedTypeList { + return slices.Clone(f.st) +} + func (f *FieldGeometry) Type() value.Type { return value.TypeGeometry } @@ -28,14 +37,35 @@ func (f *FieldGeometry) Clone() *FieldGeometry { return nil } return &FieldGeometry{ - p: f.p.Clone(), + st: f.SupportedTypes(), } } -func (f *FieldGeometry) Validate(v *value.Value) error { - return f.p.Validate(v) +func (f *FieldGeometry) Validate(v *value.Value) (err error) { + v.Match(value.Match{ + Geometry: func(a value.String) { + if a == "" { + err = ErrInvalidValue + } + }, + Default: func() { + err = ErrInvalidValue + }, + }) + return } -func (f *FieldGeometry) ValidateMultiple(v *value.Multiple) error { - return nil +func (f *FieldGeometry) ValidateMultiple(v *value.Multiple) (err error) { + vs, ok := v.ValuesString() + if !ok { + return ErrInvalidValue + } + gmap := make(map[string]struct{}) + for _, i := range vs { + if _, ok := gmap[i]; ok { + return ErrDuplicatedTag + } + gmap[i] = struct{}{} + } + return } diff --git a/server/pkg/schema/field_geometry_supported_type_test.go b/server/pkg/schema/field_geometry_supported_type_test.go new file mode 100644 index 0000000000..ad58645900 --- /dev/null +++ b/server/pkg/schema/field_geometry_supported_type_test.go @@ -0,0 +1,63 @@ +package schema + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGeometrySupportedTypeFrom(t *testing.T) { + tests := []struct { + name string + arg string + want GeometrySupportedType + }{ + { + name: "point", + arg: "point", + want: GeometrySupportedTypePoint, + }, + { + name: "multiPoint", + arg: "multiPoint", + want: GeometrySupportedTypeMultiPoint, + }, + { + name: "lineString", + arg: "lineString", + want: GeometrySupportedTypeLineString, + }, + { + name: "multiLineString", + arg: "multiLineString", + want: GeometrySupportedTypeMultiLineString, + }, + { + name: "polygon", + arg: "polygon", + want: GeometrySupportedTypePolygon, + }, + { + name: "multiPolygon", + arg: "multiPolygon", + want: GeometrySupportedTypeMultiPolygon, + }, + { + name: "geometryCollection", + arg: "geometryCollection", + want: GeometrySupportedTypeGeometryCollection, + }, + { + name: "default", + arg: "foo", + want: "", + }, + } + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(tt *testing.T) { + tt.Parallel() + assert.Equal(tt, tc.want, GeometrySupportedTypeFrom(tc.arg)) + }) + } +} diff --git a/server/pkg/schema/field_geometry_supported_types.go b/server/pkg/schema/field_geometry_supported_types.go new file mode 100644 index 0000000000..6d397cfb0d --- /dev/null +++ b/server/pkg/schema/field_geometry_supported_types.go @@ -0,0 +1,42 @@ +package schema + +import "strings" + +type GeometrySupportedType string + +const ( + GeometrySupportedTypePoint GeometrySupportedType = "POINT" + GeometrySupportedTypeMultiPoint GeometrySupportedType = "MULTIPOINT" + GeometrySupportedTypeLineString GeometrySupportedType = "LINESTRING" + GeometrySupportedTypeMultiLineString GeometrySupportedType = "MULTILINESTRING" + GeometrySupportedTypePolygon GeometrySupportedType = "POLYGON" + GeometrySupportedTypeMultiPolygon GeometrySupportedType = "MULTIPOLYGON" + GeometrySupportedTypeGeometryCollection GeometrySupportedType = "GEOMETRYCOLLECTION" +) + +func (s GeometrySupportedType) String() string { + return string(s) +} + +func GeometrySupportedTypeFrom(s string) GeometrySupportedType { + ss := strings.ToUpper(s) + switch GeometrySupportedType(ss) { + case GeometrySupportedTypePoint: + return GeometrySupportedTypePoint + case GeometrySupportedTypeMultiPoint: + return GeometrySupportedTypeMultiPoint + case GeometrySupportedTypeLineString: + return GeometrySupportedTypeLineString + case GeometrySupportedTypeMultiLineString: + return GeometrySupportedTypeMultiLineString + case GeometrySupportedTypePolygon: + return GeometrySupportedTypePolygon + case GeometrySupportedTypeMultiPolygon: + return GeometrySupportedTypeMultiPolygon + case GeometrySupportedTypeGeometryCollection: + return GeometrySupportedTypeGeometryCollection + + default: + return GeometrySupportedType("") + } +} diff --git a/server/pkg/schema/field_geometry_test.go b/server/pkg/schema/field_geometry_test.go new file mode 100644 index 0000000000..56298ca3ab --- /dev/null +++ b/server/pkg/schema/field_geometry_test.go @@ -0,0 +1,38 @@ +package schema + +import ( + "testing" + + "github.com/reearth/reearth-cms/server/pkg/value" + "github.com/stretchr/testify/assert" +) + +func TestNewGeometry(t *testing.T) { + expected := &FieldGeometry{ + st: GeometrySupportedTypeList{"point"}, + } + res := NewGeometry(GeometrySupportedTypeList{"point"}) + assert.Equal(t, expected, res) +} + +func TestFieldGeometry_Type(t *testing.T) { + assert.Equal(t, value.TypeGeometry, (&FieldGeometry{}).Type()) +} + +func TestFieldGeometry_TypeProperty(t *testing.T) { + f := FieldGeometry{} + assert.Equal(t, &TypeProperty{ + t: f.Type(), + geometry: &f, + }, (&f).TypeProperty()) +} +func TestFieldGeometry_Clone(t *testing.T) { + assert.Nil(t, (*FieldGeometry)(nil).Clone()) + assert.Equal(t, &FieldGeometry{}, (&FieldGeometry{}).Clone()) +} + +func TestFieldGeometry_Validate(t *testing.T) { + supportedType := GeometrySupportedTypePoint + assert.NoError(t, (&FieldGeometry{st: GeometrySupportedTypeList{supportedType}}).Validate(value.TypeGeometry.Value("{}"))) + assert.Equal(t, ErrInvalidValue, (&FieldGeometry{}).Validate(value.TypeText.Value(float64(1)))) +} diff --git a/server/pkg/schema/type_property_test.go b/server/pkg/schema/type_property_test.go index 57b97267e6..57a930bcfb 100644 --- a/server/pkg/schema/type_property_test.go +++ b/server/pkg/schema/type_property_test.go @@ -484,7 +484,7 @@ func TestTypeProperty_Validate(t *testing.T) { { name: "Geometry", args: args{ - tp: &TypeProperty{t: value.TypeGeometry, geometry: NewGeometry()}, + tp: &TypeProperty{t: value.TypeGeometry, geometry: NewGeometry(GeometrySupportedTypeList{"point"})}, value: value.TypeGeometry.Value("{}"), }, want: nil, From b098c886515752e1b7cb8ad196aff15d23a3dd31 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Fri, 28 Jun 2024 15:43:45 +0900 Subject: [PATCH 20/26] test: fix the test cases --- .../adapter/gql/gqlmodel/convert_schema_test.go | 8 ++++---- .../field_geometry_supported_type_test.go | 17 +++++++++++------ server/pkg/schema/field_geometry_test.go | 4 ++-- server/pkg/schema/type_property_test.go | 2 +- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/server/internal/adapter/gql/gqlmodel/convert_schema_test.go b/server/internal/adapter/gql/gqlmodel/convert_schema_test.go index b843e235ed..dcce75fcd5 100644 --- a/server/internal/adapter/gql/gqlmodel/convert_schema_test.go +++ b/server/internal/adapter/gql/gqlmodel/convert_schema_test.go @@ -211,8 +211,8 @@ func TestToSchemaFieldTypeProperty(t *testing.T) { }, { name: "geometry", - args: args{tp: schema.NewGeometry().TypeProperty()}, - want: &SchemaFieldGeometry{DefaultValue: nil}, + args: args{tp: schema.NewGeometry(schema.GeometrySupportedTypeList{"POINT"}).TypeProperty()}, + want: &SchemaFieldGeometry{SupportedTypes: []GeometrySupportedType{"POINT"}, DefaultValue: nil}, }, } for _, tt := range tests { @@ -338,10 +338,10 @@ func TestFromSchemaFieldTypeProperty(t *testing.T) { { name: "geometry", argsInp: &SchemaFieldTypePropertyInput{ - Geometry: &SchemaFieldGeometryInput{DefaultValue: nil}, + Geometry: &SchemaFieldGeometryInput{SupportedTypes: []GeometrySupportedType{"POINT"} ,DefaultValue: nil}, }, argsT: SchemaFieldTypeGeometry, - wantTp: schema.NewGeometry().TypeProperty(), + wantTp: schema.NewGeometry(schema.GeometrySupportedTypeList{"POINT"}).TypeProperty(), }, { name: "tags empty", diff --git a/server/pkg/schema/field_geometry_supported_type_test.go b/server/pkg/schema/field_geometry_supported_type_test.go index ad58645900..ef5a4cf3f3 100644 --- a/server/pkg/schema/field_geometry_supported_type_test.go +++ b/server/pkg/schema/field_geometry_supported_type_test.go @@ -17,34 +17,39 @@ func TestGeometrySupportedTypeFrom(t *testing.T) { arg: "point", want: GeometrySupportedTypePoint, }, + { + name: "point", + arg: "POINT", + want: GeometrySupportedTypePoint, + }, { name: "multiPoint", - arg: "multiPoint", + arg: "MULTIPOINT", want: GeometrySupportedTypeMultiPoint, }, { name: "lineString", - arg: "lineString", + arg: "LINESTRING", want: GeometrySupportedTypeLineString, }, { name: "multiLineString", - arg: "multiLineString", + arg: "MULTILINESTRING", want: GeometrySupportedTypeMultiLineString, }, { name: "polygon", - arg: "polygon", + arg: "POLYGON", want: GeometrySupportedTypePolygon, }, { name: "multiPolygon", - arg: "multiPolygon", + arg: "MULTIPOLYGON", want: GeometrySupportedTypeMultiPolygon, }, { name: "geometryCollection", - arg: "geometryCollection", + arg: "GEOMETRYCOLLECTION", want: GeometrySupportedTypeGeometryCollection, }, { diff --git a/server/pkg/schema/field_geometry_test.go b/server/pkg/schema/field_geometry_test.go index 56298ca3ab..3d68a369bd 100644 --- a/server/pkg/schema/field_geometry_test.go +++ b/server/pkg/schema/field_geometry_test.go @@ -9,9 +9,9 @@ import ( func TestNewGeometry(t *testing.T) { expected := &FieldGeometry{ - st: GeometrySupportedTypeList{"point"}, + st: GeometrySupportedTypeList{"POINT"}, } - res := NewGeometry(GeometrySupportedTypeList{"point"}) + res := NewGeometry(GeometrySupportedTypeList{"POINT"}) assert.Equal(t, expected, res) } diff --git a/server/pkg/schema/type_property_test.go b/server/pkg/schema/type_property_test.go index 57a930bcfb..c072dd49c2 100644 --- a/server/pkg/schema/type_property_test.go +++ b/server/pkg/schema/type_property_test.go @@ -484,7 +484,7 @@ func TestTypeProperty_Validate(t *testing.T) { { name: "Geometry", args: args{ - tp: &TypeProperty{t: value.TypeGeometry, geometry: NewGeometry(GeometrySupportedTypeList{"point"})}, + tp: &TypeProperty{t: value.TypeGeometry, geometry: NewGeometry(GeometrySupportedTypeList{"POINT"})}, value: value.TypeGeometry.Value("{}"), }, want: nil, From 58e18ad5c9ad7c3ce9f5ddc4b336a2a7afac52aa Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Fri, 28 Jun 2024 16:03:19 +0900 Subject: [PATCH 21/26] add ToGeometrySupportedType --- .../adapter/gql/gqlmodel/convert_schema.go | 24 +++++++- .../gql/gqlmodel/convert_schema_test.go | 58 +++++++++++++++++++ .../field_geometry_supported_type_test.go | 1 + 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/server/internal/adapter/gql/gqlmodel/convert_schema.go b/server/internal/adapter/gql/gqlmodel/convert_schema.go index ab82eeb517..c8d0b637e3 100644 --- a/server/internal/adapter/gql/gqlmodel/convert_schema.go +++ b/server/internal/adapter/gql/gqlmodel/convert_schema.go @@ -80,6 +80,28 @@ func ToSchemaFieldTagColor(c schema.TagColor) SchemaFieldTagColor { } +func ToGeometrySupportedType(g schema.GeometrySupportedType) GeometrySupportedType { + switch g { + case schema.GeometrySupportedTypePoint: + return GeometrySupportedTypePoint + case schema.GeometrySupportedTypeMultiPoint: + return GeometrySupportedTypeMultipoint + case schema.GeometrySupportedTypeLineString: + return GeometrySupportedTypeLinestring + case schema.GeometrySupportedTypeMultiLineString: + return GeometrySupportedTypeMultilinestring + case schema.GeometrySupportedTypePolygon: + return GeometrySupportedTypePolygon + case schema.GeometrySupportedTypeMultiPolygon: + return GeometrySupportedTypeMultipolygon + case schema.GeometrySupportedTypeGeometryCollection: + return GeometrySupportedTypeGeometrycollection + + default: + return "" + } +} + func ToSchemaFieldTypeProperty(tp *schema.TypeProperty, dv *value.Multiple, multiple bool) (res SchemaFieldTypeProperty) { tp.Match(schema.TypePropertyMatch{ Text: func(f *schema.FieldText) { @@ -245,7 +267,7 @@ func ToSchemaFieldTypeProperty(tp *schema.TypeProperty, dv *value.Multiple, mult } res = &SchemaFieldGeometry{ DefaultValue: v, - SupportedTypes: lo.Map(f.SupportedTypes(), func(v schema.GeometrySupportedType, _ int) GeometrySupportedType { return GeometrySupportedType(v) }), + SupportedTypes: lo.Map(f.SupportedTypes(), func(v schema.GeometrySupportedType, _ int) GeometrySupportedType { return ToGeometrySupportedType(v) }), } }, }) diff --git a/server/internal/adapter/gql/gqlmodel/convert_schema_test.go b/server/internal/adapter/gql/gqlmodel/convert_schema_test.go index dcce75fcd5..a1bab5350f 100644 --- a/server/internal/adapter/gql/gqlmodel/convert_schema_test.go +++ b/server/internal/adapter/gql/gqlmodel/convert_schema_test.go @@ -390,3 +390,61 @@ func TestFromCorrespondingField(t *testing.T) { got = FromCorrespondingField(cf) assert.Equal(t, want, got) } + +func TestToGeometrySupportedType(t *testing.T) { + tests := []struct { + name string + arg schema.GeometrySupportedType + want GeometrySupportedType + }{ + { + name: "point", + arg: schema.GeometrySupportedTypePoint, + want: GeometrySupportedTypePoint, + }, + { + name: "multiPoint", + arg: schema.GeometrySupportedTypeMultiPoint, + want: GeometrySupportedTypeMultipoint, + }, + { + name: "lineString", + arg: schema.GeometrySupportedTypeLineString, + want: GeometrySupportedTypeLinestring, + }, + { + name: "multiLineString", + arg: schema.GeometrySupportedTypeMultiLineString, + want: GeometrySupportedTypeMultilinestring, + }, + { + name: "polygon", + arg: schema.GeometrySupportedTypePolygon, + want: GeometrySupportedTypePolygon, + }, + { + name: "multiPolygon", + arg: schema.GeometrySupportedTypeMultiPolygon, + want: GeometrySupportedTypeMultipolygon, + }, + { + name: "geometryCollection", + arg: schema.GeometrySupportedTypeGeometryCollection, + want: GeometrySupportedTypeGeometrycollection, + }, + { + name: "default", + arg: "foo", + want: "", + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(tt *testing.T) { + tt.Parallel() + assert.Equal(tt, tc.want, ToGeometrySupportedType(tc.arg)) + }) + } +} + diff --git a/server/pkg/schema/field_geometry_supported_type_test.go b/server/pkg/schema/field_geometry_supported_type_test.go index ef5a4cf3f3..7c9db7bea9 100644 --- a/server/pkg/schema/field_geometry_supported_type_test.go +++ b/server/pkg/schema/field_geometry_supported_type_test.go @@ -58,6 +58,7 @@ func TestGeometrySupportedTypeFrom(t *testing.T) { want: "", }, } + for _, tc := range tests { tc := tc t.Run(tc.name, func(tt *testing.T) { From ac13fad78a56b0dfb1264a3e6ffe7fdf30549f4a Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Fri, 28 Jun 2024 16:46:34 +0900 Subject: [PATCH 22/26] wip: add validation to geo field --- server/go.mod | 1 + server/go.sum | 2 + server/pkg/schema/field_geometry.go | 47 ++++++++++++++------ server/pkg/schema/field_geometry_test.go | 55 ++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 13 deletions(-) diff --git a/server/go.mod b/server/go.mod index 5a162dca9c..6f2e036434 100644 --- a/server/go.mod +++ b/server/go.mod @@ -25,6 +25,7 @@ require ( github.com/kelseyhightower/envconfig v1.4.0 github.com/labstack/echo/v4 v4.11.4 github.com/oapi-codegen/runtime v1.1.1 + github.com/paulmach/go.geojson v1.5.0 github.com/ravilushqa/otelgqlgen v0.15.0 github.com/reearth/reearthx v0.0.0-20240308140749-72a08570c19b github.com/robbiet480/go.sns v0.0.0-20230523235941-e8d832c79d68 diff --git a/server/go.sum b/server/go.sum index 98ef4b14ef..666b839403 100644 --- a/server/go.sum +++ b/server/go.sum @@ -305,6 +305,8 @@ github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/paulmach/go.geojson v1.5.0 h1:7mhpMK89SQdHFcEGomT7/LuJhwhEgfmpWYVlVmLEdQw= +github.com/paulmach/go.geojson v1.5.0/go.mod h1:DgdUy2rRVDDVgKqrjMe2vZAHMfhDTrjVKt3LmHIXGbU= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28= diff --git a/server/pkg/schema/field_geometry.go b/server/pkg/schema/field_geometry.go index 45044ab221..7e79f5e9ff 100644 --- a/server/pkg/schema/field_geometry.go +++ b/server/pkg/schema/field_geometry.go @@ -1,6 +1,10 @@ package schema import ( + "encoding/json" + "strings" + + geojson "github.com/paulmach/go.geojson" "github.com/reearth/reearth-cms/server/pkg/value" "golang.org/x/exp/slices" ) @@ -41,10 +45,38 @@ func (f *FieldGeometry) Clone() *FieldGeometry { } } +// IsValidGeoJSON uses the go.geojson library to validate a GeoJSON string +func IsValidGeoJSON(data string) bool { + if len(strings.TrimSpace(data)) == 0 { + return false + } + + var raw map[string]interface{} + if err := json.Unmarshal([]byte(data), &raw); err != nil { + return false + } + + geoType, ok := raw["type"].(string) + if !ok { + return false + } + + switch geoType { + case "Feature": + _, err := geojson.UnmarshalFeature([]byte(data)) + return err == nil + case "Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon", "GeometryCollection": + _, err := geojson.UnmarshalGeometry([]byte(data)) + return err == nil + default: + return false + } +} + func (f *FieldGeometry) Validate(v *value.Value) (err error) { v.Match(value.Match{ Geometry: func(a value.String) { - if a == "" { + if !IsValidGeoJSON(a) { err = ErrInvalidValue } }, @@ -56,16 +88,5 @@ func (f *FieldGeometry) Validate(v *value.Value) (err error) { } func (f *FieldGeometry) ValidateMultiple(v *value.Multiple) (err error) { - vs, ok := v.ValuesString() - if !ok { - return ErrInvalidValue - } - gmap := make(map[string]struct{}) - for _, i := range vs { - if _, ok := gmap[i]; ok { - return ErrDuplicatedTag - } - gmap[i] = struct{}{} - } - return + return nil } diff --git a/server/pkg/schema/field_geometry_test.go b/server/pkg/schema/field_geometry_test.go index 3d68a369bd..a0db9110d0 100644 --- a/server/pkg/schema/field_geometry_test.go +++ b/server/pkg/schema/field_geometry_test.go @@ -36,3 +36,58 @@ func TestFieldGeometry_Validate(t *testing.T) { assert.NoError(t, (&FieldGeometry{st: GeometrySupportedTypeList{supportedType}}).Validate(value.TypeGeometry.Value("{}"))) assert.Equal(t, ErrInvalidValue, (&FieldGeometry{}).Validate(value.TypeText.Value(float64(1)))) } + +func TestIsValidGeoJSON(t *testing.T) { + tests := []struct { + name string + input string + expected bool + }{ + { + name: "valid GeoJSON feature", + input: `{ + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [102.0, 0.5] + }, + "properties": { + "prop0": "value0" + } + }`, + expected: true, + }, + { + name: "valid GeoJSON geometry", + input: `{ + "type": "Point", + "coordinates": [102.0, 0.5] + }`, + expected: true, + }, + { + name: "invalid GeoJSON type", + input: `{ + "type": "InvalidType", + "coordinates": [102.0, 0.5] + }`, + expected: false, + }, + { + name: "empty string", + input: ``, + expected: false, + }, + { + name: "random string", + input: `random string`, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.expected, IsValidGeoJSON(tt.input)) + }) + } +} From 57eb3745501377881588b36abbce21345b48a9cb Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Fri, 28 Jun 2024 16:57:08 +0900 Subject: [PATCH 23/26] fix: TestFieldGeometry_Validate --- server/pkg/schema/field_geometry_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/pkg/schema/field_geometry_test.go b/server/pkg/schema/field_geometry_test.go index a0db9110d0..4838ec7ee5 100644 --- a/server/pkg/schema/field_geometry_test.go +++ b/server/pkg/schema/field_geometry_test.go @@ -33,7 +33,12 @@ func TestFieldGeometry_Clone(t *testing.T) { func TestFieldGeometry_Validate(t *testing.T) { supportedType := GeometrySupportedTypePoint - assert.NoError(t, (&FieldGeometry{st: GeometrySupportedTypeList{supportedType}}).Validate(value.TypeGeometry.Value("{}"))) + geojson := `{ + "type": "Point", + "coordinates": [102.0, 0.5] + }` + assert.NoError(t, (&FieldGeometry{st: GeometrySupportedTypeList{supportedType}}).Validate(value.TypeGeometry.Value(geojson))) + assert.Equal(t, ErrInvalidValue, (&FieldGeometry{}).Validate(value.TypeText.Value("{}"))) assert.Equal(t, ErrInvalidValue, (&FieldGeometry{}).Validate(value.TypeText.Value(float64(1)))) } From b97a871a91afee721e6d0563e3e34616d30e1db8 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Fri, 28 Jun 2024 17:02:33 +0900 Subject: [PATCH 24/26] fix: TestTypeProperty_Validate --- server/pkg/schema/type_property_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/pkg/schema/type_property_test.go b/server/pkg/schema/type_property_test.go index c072dd49c2..1b3a90a7f0 100644 --- a/server/pkg/schema/type_property_test.go +++ b/server/pkg/schema/type_property_test.go @@ -485,7 +485,10 @@ func TestTypeProperty_Validate(t *testing.T) { name: "Geometry", args: args{ tp: &TypeProperty{t: value.TypeGeometry, geometry: NewGeometry(GeometrySupportedTypeList{"POINT"})}, - value: value.TypeGeometry.Value("{}"), + value: value.TypeGeometry.Value(`{ + "type": "Point", + "coordinates": [102.0, 0.5] + }`), }, want: nil, }, From 31973a6a6666853545192439ff241e9eda2896b7 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Mon, 1 Jul 2024 13:46:41 +0900 Subject: [PATCH 25/26] fix: TestValue_Match --- server/pkg/value/match_test.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/server/pkg/value/match_test.go b/server/pkg/value/match_test.go index 1dab00e1fa..bceb294e64 100644 --- a/server/pkg/value/match_test.go +++ b/server/pkg/value/match_test.go @@ -52,8 +52,12 @@ func TestValue_Match(t *testing.T) { assert.Equal(t, "default", res) res = nil - (&Value{t: TypeGeometry}).Match(Match{Default: func() { res = "default" }}) - assert.Equal(t, "default", res) + g := `{ + "type": "Point", + "coordinates": [102.0, 0.5] + }` + (&Value{t: TypeGeometry, v: g}).Match(Match{Geometry: func(v string) { res = v }}) + assert.Equal(t, g, res) } func TestOptional_Match(t *testing.T) { From 86204e3ed034c695dcde3e9498def3aa6d6a7302 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Mon, 1 Jul 2024 14:03:28 +0900 Subject: [PATCH 26/26] add FromGeometrySupportedType --- .../adapter/gql/gqlmodel/convert_schema.go | 24 +++++++- .../gql/gqlmodel/convert_schema_test.go | 58 ++++++++++++++++++- 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/server/internal/adapter/gql/gqlmodel/convert_schema.go b/server/internal/adapter/gql/gqlmodel/convert_schema.go index c8d0b637e3..f06d404852 100644 --- a/server/internal/adapter/gql/gqlmodel/convert_schema.go +++ b/server/internal/adapter/gql/gqlmodel/convert_schema.go @@ -102,6 +102,28 @@ func ToGeometrySupportedType(g schema.GeometrySupportedType) GeometrySupportedTy } } +func FromGeometrySupportedType(g GeometrySupportedType) schema.GeometrySupportedType { + switch g { + case GeometrySupportedTypePoint: + return schema.GeometrySupportedTypePoint + case GeometrySupportedTypeMultipoint: + return schema.GeometrySupportedTypeMultiPoint + case GeometrySupportedTypeLinestring: + return schema.GeometrySupportedTypeLineString + case GeometrySupportedTypeMultilinestring: + return schema.GeometrySupportedTypeMultiLineString + case GeometrySupportedTypePolygon: + return schema.GeometrySupportedTypePolygon + case GeometrySupportedTypeMultipolygon: + return schema.GeometrySupportedTypeMultiPolygon + case GeometrySupportedTypeGeometrycollection: + return schema.GeometrySupportedTypeGeometryCollection + + default: + return "" + } +} + func ToSchemaFieldTypeProperty(tp *schema.TypeProperty, dv *value.Multiple, multiple bool) (res SchemaFieldTypeProperty) { tp.Match(schema.TypePropertyMatch{ Text: func(f *schema.FieldText) { @@ -537,7 +559,7 @@ func FromSchemaTypeProperty(tp *SchemaFieldTypePropertyInput, t SchemaFieldType, dv = FromValue(SchemaFieldTypeGeometry, x.DefaultValue).AsMultiple() } tpRes = schema.NewGeometry(lo.Map(x.SupportedTypes, func(v GeometrySupportedType, _ int) schema.GeometrySupportedType { - return schema.GeometrySupportedType(v) + return FromGeometrySupportedType(v) })).TypeProperty() default: return nil, nil, ErrInvalidTypeProperty diff --git a/server/internal/adapter/gql/gqlmodel/convert_schema_test.go b/server/internal/adapter/gql/gqlmodel/convert_schema_test.go index a1bab5350f..739066047f 100644 --- a/server/internal/adapter/gql/gqlmodel/convert_schema_test.go +++ b/server/internal/adapter/gql/gqlmodel/convert_schema_test.go @@ -338,7 +338,7 @@ func TestFromSchemaFieldTypeProperty(t *testing.T) { { name: "geometry", argsInp: &SchemaFieldTypePropertyInput{ - Geometry: &SchemaFieldGeometryInput{SupportedTypes: []GeometrySupportedType{"POINT"} ,DefaultValue: nil}, + Geometry: &SchemaFieldGeometryInput{SupportedTypes: []GeometrySupportedType{"POINT"}, DefaultValue: nil}, }, argsT: SchemaFieldTypeGeometry, wantTp: schema.NewGeometry(schema.GeometrySupportedTypeList{"POINT"}).TypeProperty(), @@ -448,3 +448,59 @@ func TestToGeometrySupportedType(t *testing.T) { } } +func TestFromGeometrySupportedType(t *testing.T) { + tests := []struct { + name string + arg GeometrySupportedType + want schema.GeometrySupportedType + }{ + { + name: "point", + arg: GeometrySupportedTypePoint, + want: schema.GeometrySupportedTypePoint, + }, + { + name: "multiPoint", + arg: GeometrySupportedTypeMultipoint, + want: schema.GeometrySupportedTypeMultiPoint, + }, + { + name: "lineString", + arg: GeometrySupportedTypeLinestring, + want: schema.GeometrySupportedTypeLineString, + }, + { + name: "multiLineString", + arg: GeometrySupportedTypeMultilinestring, + want: schema.GeometrySupportedTypeMultiLineString, + }, + { + name: "polygon", + arg: GeometrySupportedTypePolygon, + want: schema.GeometrySupportedTypePolygon, + }, + { + name: "multiPolygon", + arg: GeometrySupportedTypeMultipolygon, + want: schema.GeometrySupportedTypeMultiPolygon, + }, + { + name: "geometryCollection", + arg: GeometrySupportedTypeGeometrycollection, + want: schema.GeometrySupportedTypeGeometryCollection, + }, + { + name: "default", + arg: "foo", + want: "", + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(tt *testing.T) { + tt.Parallel() + assert.Equal(tt, tc.want, FromGeometrySupportedType(tc.arg)) + }) + } +}