From 522a88d6c2fa0912faaf73bad4cdfa61810593ec Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 29 Nov 2021 15:50:00 +0900 Subject: [PATCH 01/55] rename value.OptionalValue --- pkg/dataset/value_optional.go | 6 +- pkg/dataset/value_optional_test.go | 20 ++--- pkg/property/value_optional.go | 6 +- pkg/property/value_optional_test.go | 20 ++--- pkg/value/optional.go | 22 +++--- pkg/value/optional_test.go | 114 +++++++++++++++++++++------- 6 files changed, 122 insertions(+), 66 deletions(-) diff --git a/pkg/dataset/value_optional.go b/pkg/dataset/value_optional.go index 61affc8c..c52675c8 100644 --- a/pkg/dataset/value_optional.go +++ b/pkg/dataset/value_optional.go @@ -3,7 +3,7 @@ package dataset import "github.com/reearth/reearth-backend/pkg/value" type OptionalValue struct { - ov value.OptionalValue + ov value.Optional } func NewOptionalValue(t ValueType, v *Value) *OptionalValue { @@ -11,7 +11,7 @@ func NewOptionalValue(t ValueType, v *Value) *OptionalValue { if v != nil { vv = &v.v } - ov := value.NewOptionalValue(value.Type(t), vv) + ov := value.NewOptional(value.Type(t), vv) if ov == nil { return nil } @@ -22,7 +22,7 @@ func OptionalValueFrom(v *Value) *OptionalValue { if v == nil { return nil } - ov := value.OptionalValueFrom(&v.v) + ov := value.OptionalFrom(&v.v) if ov == nil { return nil } diff --git a/pkg/dataset/value_optional_test.go b/pkg/dataset/value_optional_test.go index 8767264a..c4d6351e 100644 --- a/pkg/dataset/value_optional_test.go +++ b/pkg/dataset/value_optional_test.go @@ -23,14 +23,14 @@ func TestNewNilableValue(t *testing.T) { t: ValueTypeString, v: ValueTypeString.ValueFrom("foo"), }, - want: &OptionalValue{ov: *value.OptionalValueFrom(value.TypeString.ValueFrom("foo", nil))}, + want: &OptionalValue{ov: *value.OptionalFrom(value.TypeString.ValueFrom("foo", nil))}, }, { name: "nil value", args: args{ t: ValueTypeString, }, - want: &OptionalValue{ov: *value.NewOptionalValue(value.TypeString, nil)}, + want: &OptionalValue{ov: *value.NewOptional(value.TypeString, nil)}, }, { name: "invalid value", @@ -73,7 +73,7 @@ func TestOptionalValueFrom(t *testing.T) { args: args{ v: ValueTypeString.ValueFrom("foo"), }, - want: &OptionalValue{ov: *value.NewOptionalValue(value.TypeString, value.TypeString.ValueFrom("foo", nil))}, + want: &OptionalValue{ov: *value.NewOptional(value.TypeString, value.TypeString.ValueFrom("foo", nil))}, }, { name: "empty value", @@ -106,7 +106,7 @@ func TestOptionalValue_Type(t *testing.T) { }{ { name: "ok", - value: &OptionalValue{ov: *value.NewOptionalValue(value.TypeBool, nil)}, + value: &OptionalValue{ov: *value.NewOptional(value.TypeBool, nil)}, want: ValueTypeBool, }, { @@ -138,7 +138,7 @@ func TestOptionalValue_Value(t *testing.T) { }{ { name: "ok", - value: &OptionalValue{ov: *value.OptionalValueFrom(value.TypeString.ValueFrom("foobar", nil))}, + value: &OptionalValue{ov: *value.OptionalFrom(value.TypeString.ValueFrom("foobar", nil))}, want: ValueTypeString.ValueFrom("foobar"), }, { @@ -175,7 +175,7 @@ func TestOptionalValue_TypeAndValue(t *testing.T) { }{ { name: "ok", - value: &OptionalValue{ov: *value.OptionalValueFrom(value.TypeString.ValueFrom("foobar", nil))}, + value: &OptionalValue{ov: *value.OptionalFrom(value.TypeString.ValueFrom("foobar", nil))}, wantt: ValueTypeString, wantv: ValueTypeString.ValueFrom("foobar"), }, @@ -219,17 +219,17 @@ func TestOptionalValue_SetValue(t *testing.T) { }{ { name: "set", - value: &OptionalValue{ov: *value.OptionalValueFrom(value.TypeString.ValueFrom("foo", nil))}, + value: &OptionalValue{ov: *value.OptionalFrom(value.TypeString.ValueFrom("foo", nil))}, args: args{v: ValueTypeString.ValueFrom("foobar")}, }, { name: "set to nil", - value: &OptionalValue{ov: *value.NewOptionalValue(value.TypeString, nil)}, + value: &OptionalValue{ov: *value.NewOptional(value.TypeString, nil)}, args: args{v: ValueTypeString.ValueFrom("foobar")}, }, { name: "invalid value", - value: &OptionalValue{ov: *value.NewOptionalValue(value.TypeString, nil)}, + value: &OptionalValue{ov: *value.NewOptional(value.TypeString, nil)}, args: args{v: ValueTypeNumber.ValueFrom(1)}, invalid: true, }, @@ -279,7 +279,7 @@ func TestOptionalValue_Clone(t *testing.T) { { name: "ok", target: &OptionalValue{ - ov: *value.NewOptionalValue(value.TypeString, value.TypeString.ValueFrom("foo", nil)), + ov: *value.NewOptional(value.TypeString, value.TypeString.ValueFrom("foo", nil)), }, }, { diff --git a/pkg/property/value_optional.go b/pkg/property/value_optional.go index 6e01c84b..5a389730 100644 --- a/pkg/property/value_optional.go +++ b/pkg/property/value_optional.go @@ -3,7 +3,7 @@ package property import "github.com/reearth/reearth-backend/pkg/value" type OptionalValue struct { - ov value.OptionalValue + ov value.Optional } func NewOptionalValue(t ValueType, v *Value) *OptionalValue { @@ -11,7 +11,7 @@ func NewOptionalValue(t ValueType, v *Value) *OptionalValue { if v != nil { vv = &v.v } - ov := value.NewOptionalValue(value.Type(t), vv) + ov := value.NewOptional(value.Type(t), vv) if ov == nil { return nil } @@ -22,7 +22,7 @@ func OptionalValueFrom(v *Value) *OptionalValue { if v == nil { return nil } - ov := value.OptionalValueFrom(&v.v) + ov := value.OptionalFrom(&v.v) if ov == nil { return nil } diff --git a/pkg/property/value_optional_test.go b/pkg/property/value_optional_test.go index 61e35b02..4d16fc9f 100644 --- a/pkg/property/value_optional_test.go +++ b/pkg/property/value_optional_test.go @@ -23,14 +23,14 @@ func TestNewNilableValue(t *testing.T) { t: ValueTypeString, v: ValueTypeString.ValueFrom("foo"), }, - want: &OptionalValue{ov: *value.OptionalValueFrom(value.TypeString.ValueFrom("foo", types))}, + want: &OptionalValue{ov: *value.OptionalFrom(value.TypeString.ValueFrom("foo", types))}, }, { name: "nil value", args: args{ t: ValueTypeString, }, - want: &OptionalValue{ov: *value.NewOptionalValue(value.TypeString, nil)}, + want: &OptionalValue{ov: *value.NewOptional(value.TypeString, nil)}, }, { name: "invalid value", @@ -73,7 +73,7 @@ func TestOptionalValueFrom(t *testing.T) { args: args{ v: ValueTypeString.ValueFrom("foo"), }, - want: &OptionalValue{ov: *value.NewOptionalValue(value.TypeString, value.TypeString.ValueFrom("foo", types))}, + want: &OptionalValue{ov: *value.NewOptional(value.TypeString, value.TypeString.ValueFrom("foo", types))}, }, { name: "empty value", @@ -106,7 +106,7 @@ func TestOptionalValue_Type(t *testing.T) { }{ { name: "ok", - value: &OptionalValue{ov: *value.NewOptionalValue(value.TypeBool, nil)}, + value: &OptionalValue{ov: *value.NewOptional(value.TypeBool, nil)}, want: ValueTypeBool, }, { @@ -138,7 +138,7 @@ func TestOptionalValue_Value(t *testing.T) { }{ { name: "ok", - value: &OptionalValue{ov: *value.OptionalValueFrom(value.TypeString.ValueFrom("foobar", types))}, + value: &OptionalValue{ov: *value.OptionalFrom(value.TypeString.ValueFrom("foobar", types))}, want: ValueTypeString.ValueFrom("foobar"), }, { @@ -175,7 +175,7 @@ func TestOptionalValue_TypeAndValue(t *testing.T) { }{ { name: "ok", - value: &OptionalValue{ov: *value.OptionalValueFrom(value.TypeString.ValueFrom("foobar", types))}, + value: &OptionalValue{ov: *value.OptionalFrom(value.TypeString.ValueFrom("foobar", types))}, wantt: ValueTypeString, wantv: ValueTypeString.ValueFrom("foobar"), }, @@ -219,17 +219,17 @@ func TestOptionalValue_SetValue(t *testing.T) { }{ { name: "set", - value: &OptionalValue{ov: *value.OptionalValueFrom(value.TypeString.ValueFrom("foo", types))}, + value: &OptionalValue{ov: *value.OptionalFrom(value.TypeString.ValueFrom("foo", types))}, args: args{v: ValueTypeString.ValueFrom("foobar")}, }, { name: "set to nil", - value: &OptionalValue{ov: *value.NewOptionalValue(value.TypeString, nil)}, + value: &OptionalValue{ov: *value.NewOptional(value.TypeString, nil)}, args: args{v: ValueTypeString.ValueFrom("foobar")}, }, { name: "invalid value", - value: &OptionalValue{ov: *value.NewOptionalValue(value.TypeString, nil)}, + value: &OptionalValue{ov: *value.NewOptional(value.TypeString, nil)}, args: args{v: ValueTypeNumber.ValueFrom(1)}, invalid: true, }, @@ -279,7 +279,7 @@ func TestOptionalValue_Clone(t *testing.T) { { name: "ok", target: &OptionalValue{ - ov: *value.NewOptionalValue(value.TypeString, value.TypeString.ValueFrom("foo", types)), + ov: *value.NewOptional(value.TypeString, value.TypeString.ValueFrom("foo", types)), }, }, { diff --git a/pkg/value/optional.go b/pkg/value/optional.go index 2b0b230e..89134e2a 100644 --- a/pkg/value/optional.go +++ b/pkg/value/optional.go @@ -1,60 +1,60 @@ package value -type OptionalValue struct { +type Optional struct { t Type v *Value } -func NewOptionalValue(t Type, v *Value) *OptionalValue { +func NewOptional(t Type, v *Value) *Optional { if t == TypeUnknown || (v != nil && v.Type() != t) { return nil } - return &OptionalValue{ + return &Optional{ t: t, v: v, } } -func OptionalValueFrom(v *Value) *OptionalValue { +func OptionalFrom(v *Value) *Optional { if v.Type() == TypeUnknown { return nil } - return &OptionalValue{ + return &Optional{ t: v.Type(), v: v, } } -func (ov *OptionalValue) Type() Type { +func (ov *Optional) Type() Type { if ov == nil { return TypeUnknown } return ov.t } -func (ov *OptionalValue) Value() *Value { +func (ov *Optional) Value() *Value { if ov == nil || ov.t == TypeUnknown || ov.v == nil { return nil } return ov.v.Clone() } -func (ov *OptionalValue) TypeAndValue() (Type, *Value) { +func (ov *Optional) TypeAndValue() (Type, *Value) { return ov.Type(), ov.Value() } -func (ov *OptionalValue) SetValue(v *Value) { +func (ov *Optional) SetValue(v *Value) { if ov == nil || ov.t == TypeUnknown || (v != nil && ov.t != v.Type()) { return } ov.v = v.Clone() } -func (ov *OptionalValue) Clone() *OptionalValue { +func (ov *Optional) Clone() *Optional { if ov == nil { return nil } - return &OptionalValue{ + return &Optional{ t: ov.t, v: ov.v.Clone(), } diff --git a/pkg/value/optional_test.go b/pkg/value/optional_test.go index 19e0f601..ef5365fd 100644 --- a/pkg/value/optional_test.go +++ b/pkg/value/optional_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestNewOptionalValue(t *testing.T) { +func TestNewOptional(t *testing.T) { type args struct { t Type v *Value @@ -14,7 +14,7 @@ func TestNewOptionalValue(t *testing.T) { tests := []struct { name string args args - want *OptionalValue + want *Optional }{ { name: "default type", @@ -22,7 +22,7 @@ func TestNewOptionalValue(t *testing.T) { t: TypeString, v: TypeString.ValueFrom("foo", nil), }, - want: &OptionalValue{t: TypeString, v: TypeString.ValueFrom("foo", nil)}, + want: &Optional{t: TypeString, v: TypeString.ValueFrom("foo", nil)}, }, { name: "custom type", @@ -30,14 +30,14 @@ func TestNewOptionalValue(t *testing.T) { t: Type("foo"), v: &Value{t: Type("foo")}, }, - want: &OptionalValue{t: Type("foo"), v: &Value{t: Type("foo")}}, + want: &Optional{t: Type("foo"), v: &Value{t: Type("foo")}}, }, { name: "nil value", args: args{ t: Type("foo"), }, - want: &OptionalValue{t: Type("foo"), v: nil}, + want: &Optional{t: Type("foo"), v: nil}, }, { name: "invalid value", @@ -61,33 +61,33 @@ func TestNewOptionalValue(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - assert.Equal(t, tt.want, NewOptionalValue(tt.args.t, tt.args.v)) + assert.Equal(t, tt.want, NewOptional(tt.args.t, tt.args.v)) }) } } -func TestOptionalValueFrom(t *testing.T) { +func TestOptionalFrom(t *testing.T) { type args struct { v *Value } tests := []struct { name string args args - want *OptionalValue + want *Optional }{ { name: "default type", args: args{ v: TypeString.ValueFrom("foo", nil), }, - want: &OptionalValue{t: TypeString, v: TypeString.ValueFrom("foo", nil)}, + want: &Optional{t: TypeString, v: TypeString.ValueFrom("foo", nil)}, }, { name: "custom type", args: args{ v: &Value{t: Type("foo")}, }, - want: &OptionalValue{t: Type("foo"), v: &Value{t: Type("foo")}}, + want: &Optional{t: Type("foo"), v: &Value{t: Type("foo")}}, }, { name: "invalid value", @@ -107,7 +107,7 @@ func TestOptionalValueFrom(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - assert.Equal(t, tt.want, OptionalValueFrom(tt.args.v)) + assert.Equal(t, tt.want, OptionalFrom(tt.args.v)) }) } } @@ -115,17 +115,17 @@ func TestOptionalValueFrom(t *testing.T) { func TestOptionalValue_Type(t *testing.T) { tests := []struct { name string - value *OptionalValue + value *Optional want Type }{ { name: "ok", - value: &OptionalValue{t: Type("foo")}, + value: &Optional{t: Type("foo")}, want: Type("foo"), }, { name: "empty", - value: &OptionalValue{}, + value: &Optional{}, want: TypeUnknown, }, { @@ -147,17 +147,17 @@ func TestOptionalValue_Type(t *testing.T) { func TestOptionalValue_Value(t *testing.T) { tests := []struct { name string - value *OptionalValue + value *Optional want *Value }{ { name: "ok", - value: &OptionalValue{t: TypeString, v: &Value{t: TypeString, v: "foobar"}}, + value: &Optional{t: TypeString, v: &Value{t: TypeString, v: "foobar"}}, want: &Value{t: TypeString, v: "foobar"}, }, { name: "empty", - value: &OptionalValue{}, + value: &Optional{}, want: nil, }, { @@ -183,19 +183,19 @@ func TestOptionalValue_Value(t *testing.T) { func TestOptionalValue_TypeAndValue(t *testing.T) { tests := []struct { name string - value *OptionalValue + value *Optional wantt Type wantv *Value }{ { name: "ok", - value: &OptionalValue{t: TypeString, v: &Value{t: TypeString, v: "foobar"}}, + value: &Optional{t: TypeString, v: &Value{t: TypeString, v: "foobar"}}, wantt: TypeString, wantv: &Value{t: TypeString, v: "foobar"}, }, { name: "empty", - value: &OptionalValue{}, + value: &Optional{}, wantt: TypeUnknown, wantv: nil, }, @@ -227,13 +227,13 @@ func TestOptionalValue_SetValue(t *testing.T) { } tests := []struct { name string - value *OptionalValue + value *Optional args args invalid bool }{ { name: "set", - value: &OptionalValue{ + value: &Optional{ t: TypeString, v: &Value{t: TypeString, v: "foobar"}, }, @@ -241,14 +241,14 @@ func TestOptionalValue_SetValue(t *testing.T) { }, { name: "set to nil", - value: &OptionalValue{ + value: &Optional{ t: TypeString, }, args: args{v: &Value{t: TypeString, v: "bar"}}, }, { name: "invalid value", - value: &OptionalValue{ + value: &Optional{ t: TypeNumber, v: &Value{t: TypeNumber, v: 1}, }, @@ -257,14 +257,14 @@ func TestOptionalValue_SetValue(t *testing.T) { }, { name: "nil value", - value: &OptionalValue{ + value: &Optional{ t: TypeNumber, v: &Value{t: TypeNumber, v: 1}, }, }, { name: "empty", - value: &OptionalValue{}, + value: &Optional{}, args: args{v: &Value{t: TypeString, v: "bar"}}, invalid: true, }, @@ -302,15 +302,15 @@ func TestOptionalValue_SetValue(t *testing.T) { func TestOptionalValue_Clone(t *testing.T) { tests := []struct { name string - target *OptionalValue + target *Optional }{ { name: "ok", - target: &OptionalValue{t: TypeString, v: TypeString.ValueFrom("foo", nil)}, + target: &Optional{t: TypeString, v: TypeString.ValueFrom("foo", nil)}, }, { name: "empty", - target: &OptionalValue{}, + target: &Optional{}, }, { name: "nil", @@ -328,3 +328,59 @@ func TestOptionalValue_Clone(t *testing.T) { }) } } + +func TestOptional_Cast(t *testing.T) { + type args struct { + t Type + p TypePropertyMap + } + tests := []struct { + name string + target *Optional + args args + want *Optional + }{ + { + name: "diff type", + target: &Optional{t: TypeNumber, v: TypeNumber.ValueFrom(1.1, nil)}, + args: args{t: TypeString}, + want: &Optional{t: TypeString, v: TypeString.ValueFrom("1.1", nil)}, + }, + { + name: "same type", + target: &Optional{t: TypeNumber, v: TypeNumber.ValueFrom(1.1, nil)}, + args: args{t: TypeNumber}, + want: &Optional{t: TypeNumber, v: TypeNumber.ValueFrom(1.1, nil)}, + }, + { + name: "nil value", + target: &Optional{t: TypeNumber}, + args: args{t: TypeString}, + want: &Optional{t: TypeString}, + }, + { + name: "failed to cast", + target: &Optional{t: TypeLatLng, v: TypeLatLng.ValueFrom(LatLng{Lat: 1, Lng: 2}, nil)}, + args: args{t: TypeString}, + want: nil, + }, + { + name: "empty", + target: &Optional{}, + args: args{t: TypeString}, + want: nil, + }, + { + name: "nil", + target: nil, + args: args{t: TypeString}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Cast(tt.args.t, tt.args.p)) + }) + } +} From 9039174ad5b95af5b6f5a92135a5103f998d8c39 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 29 Nov 2021 16:26:23 +0900 Subject: [PATCH 02/55] add cast method --- pkg/dataset/value_optional.go | 11 ++++++ pkg/dataset/value_optional_test.go | 49 +++++++++++++++++++++++++ pkg/property/value_optional.go | 11 ++++++ pkg/property/value_optional_test.go | 49 +++++++++++++++++++++++++ pkg/value/optional.go | 17 +++++++++ pkg/value/string.go | 5 +++ pkg/value/value.go | 10 ++++++ pkg/value/value_test.go | 56 +++++++++++++++++++++++++++++ 8 files changed, 208 insertions(+) diff --git a/pkg/dataset/value_optional.go b/pkg/dataset/value_optional.go index c52675c8..ac422506 100644 --- a/pkg/dataset/value_optional.go +++ b/pkg/dataset/value_optional.go @@ -76,3 +76,14 @@ func (ov *OptionalValue) Clone() *OptionalValue { ov: *nov, } } + +func (ov *OptionalValue) Cast(t ValueType) *OptionalValue { + if ov == nil { + return nil + } + vv := ov.ov.Cast(value.Type(t), nil) + if vv == nil { + return nil + } + return &OptionalValue{ov: *vv} +} diff --git a/pkg/dataset/value_optional_test.go b/pkg/dataset/value_optional_test.go index c4d6351e..82f82660 100644 --- a/pkg/dataset/value_optional_test.go +++ b/pkg/dataset/value_optional_test.go @@ -301,3 +301,52 @@ func TestOptionalValue_Clone(t *testing.T) { }) } } + +func TestOptionalValue_Cast(t *testing.T) { + type args struct { + t ValueType + } + tests := []struct { + name string + target *OptionalValue + args args + want *OptionalValue + }{ + { + name: "diff type", + target: &OptionalValue{ov: *value.OptionalFrom(value.TypeNumber.ValueFrom(1.1, nil))}, + args: args{t: ValueTypeString}, + want: &OptionalValue{ov: *value.OptionalFrom(value.TypeString.ValueFrom("1.1", nil))}, + }, + { + name: "same type", + target: &OptionalValue{ov: *value.OptionalFrom(value.TypeNumber.ValueFrom(1.1, nil))}, + args: args{t: ValueTypeNumber}, + want: &OptionalValue{ov: *value.OptionalFrom(value.TypeNumber.ValueFrom(1.1, nil))}, + }, + { + name: "failed to cast", + target: &OptionalValue{ov: *value.OptionalFrom(value.TypeLatLng.ValueFrom(LatLng{Lat: 1, Lng: 2}, nil))}, + args: args{t: ValueTypeString}, + want: nil, + }, + { + name: "empty", + target: &OptionalValue{}, + args: args{t: ValueTypeString}, + want: nil, + }, + { + name: "nil", + target: nil, + args: args{t: ValueTypeString}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Cast(tt.args.t)) + }) + } +} diff --git a/pkg/property/value_optional.go b/pkg/property/value_optional.go index 5a389730..6b862ad6 100644 --- a/pkg/property/value_optional.go +++ b/pkg/property/value_optional.go @@ -76,3 +76,14 @@ func (ov *OptionalValue) SetValue(v *Value) { ov.ov.SetValue(&v.v) } } + +func (ov *OptionalValue) Cast(t ValueType) *OptionalValue { + if ov == nil { + return nil + } + vv := ov.ov.Cast(value.Type(t), types) + if vv == nil { + return nil + } + return &OptionalValue{ov: *vv} +} diff --git a/pkg/property/value_optional_test.go b/pkg/property/value_optional_test.go index 4d16fc9f..6b1710b4 100644 --- a/pkg/property/value_optional_test.go +++ b/pkg/property/value_optional_test.go @@ -301,3 +301,52 @@ func TestOptionalValue_Clone(t *testing.T) { }) } } + +func TestOptionalValue_Cast(t *testing.T) { + type args struct { + t ValueType + } + tests := []struct { + name string + target *OptionalValue + args args + want *OptionalValue + }{ + { + name: "diff type", + target: &OptionalValue{ov: *value.OptionalFrom(value.TypeNumber.ValueFrom(1.1, types))}, + args: args{t: ValueTypeString}, + want: &OptionalValue{ov: *value.OptionalFrom(value.TypeString.ValueFrom("1.1", types))}, + }, + { + name: "same type", + target: &OptionalValue{ov: *value.OptionalFrom(value.TypeNumber.ValueFrom(1.1, types))}, + args: args{t: ValueTypeNumber}, + want: &OptionalValue{ov: *value.OptionalFrom(value.TypeNumber.ValueFrom(1.1, types))}, + }, + { + name: "failed to cast", + target: &OptionalValue{ov: *value.OptionalFrom(value.TypeLatLng.ValueFrom(LatLng{Lat: 1, Lng: 2}, types))}, + args: args{t: ValueTypeString}, + want: nil, + }, + { + name: "empty", + target: &OptionalValue{}, + args: args{t: ValueTypeString}, + want: nil, + }, + { + name: "nil", + target: nil, + args: args{t: ValueTypeString}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Cast(tt.args.t)) + }) + } +} diff --git a/pkg/value/optional.go b/pkg/value/optional.go index 89134e2a..0c6557ee 100644 --- a/pkg/value/optional.go +++ b/pkg/value/optional.go @@ -59,3 +59,20 @@ func (ov *Optional) Clone() *Optional { v: ov.v.Clone(), } } + +// Cast tries to convert the value to the new type and generates a new Optional. If cast was failed, it returns nil. +func (ov *Optional) Cast(t Type, p TypePropertyMap) *Optional { + if ov == nil || ov.t == TypeUnknown { + return nil + } + if ov.v == nil { + return NewOptional(t, nil) + } + + nv := ov.v.Cast(t, p) + if nv == nil { + return nil // failed to cast + } + + return NewOptional(t, nv) +} diff --git a/pkg/value/string.go b/pkg/value/string.go index 3979d0cb..15341a42 100644 --- a/pkg/value/string.go +++ b/pkg/value/string.go @@ -1,5 +1,7 @@ package value +import "strconv" + var TypeString Type = "string" type propertyString struct{} @@ -11,6 +13,9 @@ func (*propertyString) I2V(i interface{}) (interface{}, bool) { if v, ok := i.(*string); ok { return *v, true } + if v, ok := i.(float64); ok { + return strconv.FormatFloat(v, 'f', -1, 64), true + } return nil, false } diff --git a/pkg/value/value.go b/pkg/value/value.go index 79cea656..aac797f1 100644 --- a/pkg/value/value.go +++ b/pkg/value/value.go @@ -80,3 +80,13 @@ func (v *Value) Validate() bool { func (v *Value) MarshalJSON() ([]byte, error) { return json.Marshal(v.Interface()) } + +func (v *Value) Cast(t Type, p TypePropertyMap) *Value { + if v == nil || v.t == TypeUnknown { + return nil + } + if v.t == t { + return v.Clone() + } + return t.ValueFrom(v.v, p) +} diff --git a/pkg/value/value_test.go b/pkg/value/value_test.go index b71a78fb..34c47320 100644 --- a/pkg/value/value_test.go +++ b/pkg/value/value_test.go @@ -262,3 +262,59 @@ func TestValue_Interface(t *testing.T) { }) } } + +func TestValue_Cast(t *testing.T) { + type args struct { + t Type + p TypePropertyMap + } + tests := []struct { + name string + target *Value + args args + want *Value + }{ + { + name: "diff type", + target: &Value{t: TypeNumber, v: 1.1}, + args: args{t: TypeString}, + want: &Value{t: TypeString, v: "1.1"}, + }, + { + name: "same type", + target: &Value{t: TypeNumber, v: 1.1}, + args: args{t: TypeNumber}, + want: &Value{t: TypeNumber, v: 1.1}, + }, + { + name: "failed to cast", + target: &Value{t: TypeLatLng, v: LatLng{Lat: 1, Lng: 2}}, + args: args{t: TypeString}, + want: nil, + }, + { + name: "invalid value", + target: &Value{t: TypeNumber}, + args: args{t: TypeString}, + want: nil, + }, + { + name: "empty", + target: &Value{}, + args: args{t: TypeString}, + want: nil, + }, + { + name: "nil", + target: nil, + args: args{t: TypeString}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Cast(tt.args.t, tt.args.p)) + }) + } +} From 9b8a7ed5ecc3d25b6b78b8a8d16c170c26b253cf Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 1 Dec 2021 13:53:32 +0900 Subject: [PATCH 03/55] add Pointer, GraphPointer, Migrator to dataset --- pkg/dataset/dataset.go | 9 + pkg/dataset/graph_loader.go | 8 + pkg/dataset/graph_pointer.go | 155 +++++++ pkg/dataset/graph_pointer_test.go | 693 ++++++++++++++++++++++++++++++ pkg/dataset/id.go | 24 ++ pkg/dataset/loader.go | 19 + pkg/dataset/migrator.go | 113 +++++ pkg/dataset/migrator_test.go | 620 ++++++++++++++++++++++++++ pkg/dataset/pointer.go | 76 ++++ pkg/dataset/pointer_test.go | 364 ++++++++++++++++ pkg/dataset/schema.go | 9 +- 11 files changed, 2088 insertions(+), 2 deletions(-) create mode 100644 pkg/dataset/graph_pointer.go create mode 100644 pkg/dataset/graph_pointer_test.go create mode 100644 pkg/dataset/id.go create mode 100644 pkg/dataset/migrator.go create mode 100644 pkg/dataset/migrator_test.go create mode 100644 pkg/dataset/pointer.go create mode 100644 pkg/dataset/pointer_test.go diff --git a/pkg/dataset/dataset.go b/pkg/dataset/dataset.go index f06678ed..085c5fb6 100644 --- a/pkg/dataset/dataset.go +++ b/pkg/dataset/dataset.go @@ -57,6 +57,15 @@ func (d *Dataset) Field(id id.DatasetSchemaFieldID) *Field { return d.fields[id] } +func (d *Dataset) FieldByPointer(p *Pointer) *Field { + if d == nil || p.IsEmpty() || d.Schema() != p.Schema() { + return nil + } else if pd := p.Dataset(); pd != nil && d.ID() != *pd { + return nil + } + return d.Field(p.Field()) +} + func (d *Dataset) FieldRef(id *id.DatasetSchemaFieldID) *Field { if d == nil || id == nil { return nil diff --git a/pkg/dataset/graph_loader.go b/pkg/dataset/graph_loader.go index a613abf4..ee312476 100644 --- a/pkg/dataset/graph_loader.go +++ b/pkg/dataset/graph_loader.go @@ -35,3 +35,11 @@ func GraphLoaderFromMapAndGraph(m Map, g GraphLoader) GraphLoader { return g(ctx, root, fields...) } } + +func (l GraphLoader) ByGraphPointer(ctx context.Context, p *GraphPointer) (List, *Field, error) { + d := p.First().Dataset() + if d == nil { + return nil, nil, nil + } + return l(ctx, *d, p.Fields()...) +} diff --git a/pkg/dataset/graph_pointer.go b/pkg/dataset/graph_pointer.go new file mode 100644 index 00000000..f728ee9e --- /dev/null +++ b/pkg/dataset/graph_pointer.go @@ -0,0 +1,155 @@ +package dataset + +type GraphPointer struct { + pointers []*Pointer +} + +func NewGraphPointer(p []*Pointer) *GraphPointer { + if len(p) == 0 || p[0].Dataset() == nil { + return nil + } + pointers := make([]*Pointer, 0, len(p)) + for _, l := range p { + if l == nil { + continue + } + pointers = append(pointers, l.Clone()) + } + return &GraphPointer{ + pointers: pointers, + } +} + +func (l *GraphPointer) Clone() *GraphPointer { + if l.IsEmpty() { + return nil + } + return &GraphPointer{ + pointers: append([]*Pointer{}, l.pointers...), + } +} + +func (l *GraphPointer) WithDataset(ds ID) *GraphPointer { + if l.IsEmpty() { + return nil + } + + links := l.Clone() + first := l.First() + links.pointers[0] = first.PointAt(&ds) + return links +} + +func (l *GraphPointer) IsEmpty() bool { + return l == nil || len(l.pointers) == 0 +} + +func (l *GraphPointer) IsLinkedFully() bool { + return !l.IsEmpty() && len(l.Datasets()) == len(l.pointers) +} + +func (l *GraphPointer) Len() int { + if l.IsEmpty() { + return 0 + } + return len(l.pointers) +} + +func (l *GraphPointer) First() *Pointer { + if l.IsEmpty() { + return nil + } + return l.pointers[0] +} + +func (l *GraphPointer) Last() *Pointer { + if l.IsEmpty() { + return nil + } + return l.pointers[len(l.pointers)-1] +} + +func (l *GraphPointer) Pointers() []*Pointer { + if l == nil || len(l.pointers) == 0 { + return nil + } + return append([]*Pointer{}, l.pointers...) +} + +func (l *GraphPointer) Datasets() []ID { + if l.IsEmpty() { + return nil + } + datasets := make([]ID, 0, len(l.pointers)) + for _, i := range l.pointers { + if d := i.Dataset(); d != nil { + datasets = append(datasets, *d) + } else { + return datasets + } + } + return datasets +} + +func (l *GraphPointer) Schemas() []SchemaID { + if l.IsEmpty() { + return nil + } + schemas := make([]SchemaID, 0, len(l.pointers)) + for _, i := range l.pointers { + schemas = append(schemas, i.Schema()) + } + return schemas +} + +func (l *GraphPointer) Fields() []FieldID { + if l.IsEmpty() { + return nil + } + fields := make([]FieldID, 0, len(l.pointers)) + for _, i := range l.pointers { + fields = append(fields, i.Field()) + } + return fields +} + +func (l *GraphPointer) HasDataset(did ID) bool { + if l.IsEmpty() { + return false + } + for _, l2 := range l.pointers { + if d := l2.Dataset(); d != nil && *d == did { + return true + } + } + return false +} + +func (l *GraphPointer) HasSchema(dsid SchemaID) bool { + if l.IsEmpty() { + return false + } + for _, l2 := range l.pointers { + if l2.Schema() == dsid { + return true + } + } + return false +} + +func (l *GraphPointer) HasSchemaAndDataset(dsid SchemaID, did ID) bool { + if l.IsEmpty() { + return false + } + + for _, l2 := range l.pointers { + if l2 == nil || l2.Schema() != dsid { + continue + } + if d := l2.Dataset(); d != nil && *d == did { + return true + } + } + + return false +} diff --git a/pkg/dataset/graph_pointer_test.go b/pkg/dataset/graph_pointer_test.go new file mode 100644 index 00000000..8646f73a --- /dev/null +++ b/pkg/dataset/graph_pointer_test.go @@ -0,0 +1,693 @@ +package dataset + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewGraphPointer(t *testing.T) { + d := NewID() + s := NewSchemaID() + f := NewFieldID() + + type args struct { + p []*Pointer + } + tests := []struct { + name string + args args + want *GraphPointer + }{ + { + name: "ok", + args: args{ + p: []*Pointer{PointAt(d, s, f), nil, PointAtField(s, f)}, + }, + want: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s, f)}, + }, + }, + { + name: "invalid", + args: args{ + p: []*Pointer{PointAtField(s, f)}, + }, + want: nil, + }, + { + name: "empty", + args: args{ + p: []*Pointer{}, + }, + want: nil, + }, + { + name: "nil", + args: args{ + p: nil, + }, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, NewGraphPointer(tt.args.p)) + }) + } +} + +func TestGraphPointer_Clone(t *testing.T) { + d := NewID() + s := NewSchemaID() + f := NewFieldID() + + tests := []struct { + name string + target *GraphPointer + want *GraphPointer + }{ + { + name: "ok", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAt(d, s, f)}, + }, + want: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAt(d, s, f)}, + }, + }, + { + name: "empty", + target: &GraphPointer{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := tt.target.Clone() + assert.Equal(t, tt.want, res) + if tt.want != nil { + assert.NotSame(t, tt.target, res) + } + }) + } +} + +func TestGraphPointer_WithDataset(t *testing.T) { + d := NewID() + d2 := NewID() + s := NewSchemaID() + f := NewFieldID() + + type args struct { + ds ID + } + tests := []struct { + name string + target *GraphPointer + args args + want *GraphPointer + }{ + { + name: "ok", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAt(d, s, f)}, + }, + args: args{ + ds: d2, + }, + want: &GraphPointer{ + []*Pointer{PointAt(d2, s, f), PointAt(d, s, f)}, + }, + }, + { + name: "empty", + target: &GraphPointer{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.WithDataset(tt.args.ds)) + }) + } +} + +func TestGraphPointer_IsEmpty(t *testing.T) { + d := NewID() + s := NewSchemaID() + f := NewFieldID() + + tests := []struct { + name string + target *GraphPointer + want bool + }{ + { + name: "present", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f)}, + }, + want: false, + }, + { + name: "empty", + target: &GraphPointer{}, + want: true, + }, + { + name: "nil", + target: nil, + want: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.IsEmpty()) + }) + } +} + +func TestGraphPointer_IsLinkedFully(t *testing.T) { + d := NewID() + s := NewSchemaID() + f := NewFieldID() + + tests := []struct { + name string + target *GraphPointer + want bool + }{ + { + name: "ok", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f)}, + }, + want: true, + }, + { + name: "false", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s, f)}, + }, + want: false, + }, + { + name: "empty", + target: &GraphPointer{}, + want: false, + }, + { + name: "nil", + target: nil, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.IsLinkedFully()) + }) + } +} + +func TestGraphPointer_Len(t *testing.T) { + d := NewID() + s := NewSchemaID() + f := NewFieldID() + + tests := []struct { + name string + target *GraphPointer + want int + }{ + { + name: "1", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f)}, + }, + want: 1, + }, + { + name: "2", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s, f)}, + }, + want: 2, + }, + { + name: "empty", + target: &GraphPointer{}, + want: 0, + }, + { + name: "nil", + target: nil, + want: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Len()) + }) + } +} + +func TestGraphPointer_First(t *testing.T) { + d := NewID() + s := NewSchemaID() + f := NewFieldID() + + tests := []struct { + name string + target *GraphPointer + want *Pointer + }{ + { + name: "ok", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s, f)}, + }, + want: PointAt(d, s, f), + }, + { + name: "empty", + target: &GraphPointer{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.First()) + }) + } +} + +func TestGraphPointer_Last(t *testing.T) { + d := NewID() + s := NewSchemaID() + f := NewFieldID() + + tests := []struct { + name string + target *GraphPointer + want *Pointer + }{ + { + name: "ok", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s, f)}, + }, + want: PointAtField(s, f), + }, + { + name: "empty", + target: &GraphPointer{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Last()) + }) + } +} + +func TestGraphPointer_Pointers(t *testing.T) { + d := NewID() + s := NewSchemaID() + f := NewFieldID() + + tests := []struct { + name string + target *GraphPointer + want []*Pointer + }{ + { + name: "ok", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s, f)}, + }, + want: []*Pointer{PointAt(d, s, f), PointAtField(s, f)}, + }, + { + name: "empty", + target: &GraphPointer{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := tt.target.Pointers() + assert.Equal(t, tt.want, res) + if len(res) > 0 { + res2 := append([]*Pointer{}, res...) + res[0] = nil + assert.Equal(t, res2, tt.target.Pointers()) // result not changed + } + }) + } +} + +func TestGraphPointer_Datasets(t *testing.T) { + d := NewID() + d2 := NewID() + s := NewSchemaID() + f := NewFieldID() + + tests := []struct { + name string + target *GraphPointer + want []ID + }{ + { + name: "ok", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s, f)}, + }, + want: []ID{d}, + }, + { + name: "ok2", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAt(d2, s, f)}, + }, + want: []ID{d, d2}, + }, + { + name: "empty", + target: &GraphPointer{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Datasets()) + }) + } +} + +func TestGraphPointer_Schemas(t *testing.T) { + d := NewID() + s := NewSchemaID() + s2 := NewSchemaID() + f := NewFieldID() + + tests := []struct { + name string + target *GraphPointer + want []SchemaID + }{ + { + name: "ok", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s2, f)}, + }, + want: []SchemaID{s, s2}, + }, + { + name: "empty", + target: &GraphPointer{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Schemas()) + }) + } +} + +func TestGraphPointer_Fields(t *testing.T) { + d := NewID() + s := NewSchemaID() + f := NewFieldID() + f2 := NewFieldID() + + tests := []struct { + name string + target *GraphPointer + want []FieldID + }{ + { + name: "ok", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s, f2)}, + }, + want: []FieldID{f, f2}, + }, + { + name: "empty", + target: &GraphPointer{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Fields()) + }) + } +} + +func TestGraphPointer_HasDataset(t *testing.T) { + d := NewID() + d2 := NewID() + s := NewSchemaID() + f := NewFieldID() + + type args struct { + did ID + } + tests := []struct { + name string + target *GraphPointer + args args + want bool + }{ + { + name: "found", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s, f)}, + }, + args: args{ + did: d, + }, + want: true, + }, + { + name: "not found", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s, f)}, + }, + args: args{ + did: d2, + }, + want: false, + }, + { + name: "empty", + target: &GraphPointer{}, + args: args{ + did: d, + }, + want: false, + }, + { + name: "nil", + target: nil, + args: args{ + did: d, + }, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.target.HasDataset(tt.args.did); got != tt.want { + assert.Equal(t, tt.want, tt.target.HasDataset(tt.args.did)) + } + }) + } +} + +func TestGraphPointer_HasSchema(t *testing.T) { + d := NewID() + s := NewSchemaID() + s2 := NewSchemaID() + s3 := NewSchemaID() + f := NewFieldID() + + type args struct { + dsid SchemaID + } + tests := []struct { + name string + target *GraphPointer + args args + want bool + }{ + { + name: "found", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s2, f)}, + }, + args: args{ + dsid: s2, + }, + want: true, + }, + { + name: "not found", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s2, f)}, + }, + args: args{ + dsid: s3, + }, + want: false, + }, + { + name: "empty", + target: &GraphPointer{}, + args: args{ + dsid: s, + }, + want: false, + }, + { + name: "nil", + target: nil, + args: args{ + dsid: s, + }, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.target.HasSchema(tt.args.dsid); got != tt.want { + assert.Equal(t, tt.want, tt.target.HasSchema(tt.args.dsid)) + } + }) + } +} + +func TestGraphPointer_HasSchemaAndDataset(t *testing.T) { + d := NewID() + d2 := NewID() + s := NewSchemaID() + s2 := NewSchemaID() + f := NewFieldID() + f2 := NewFieldID() + + type args struct { + dsid SchemaID + did ID + } + tests := []struct { + name string + target *GraphPointer + args args + want bool + }{ + { + name: "true", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s2, f2)}, + }, + args: args{ + dsid: s, + did: d, + }, + want: true, + }, + { + name: "false", + target: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAtField(s2, f2)}, + }, + args: args{ + dsid: s2, + did: d2, + }, + want: false, + }, + { + name: "empty", + target: &GraphPointer{}, + args: args{ + dsid: s, + did: d, + }, + want: false, + }, + { + name: "nil", + target: nil, + args: args{ + dsid: s, + did: d, + }, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.HasSchemaAndDataset(tt.args.dsid, tt.args.did)) + }) + } +} diff --git a/pkg/dataset/id.go b/pkg/dataset/id.go new file mode 100644 index 00000000..781edc77 --- /dev/null +++ b/pkg/dataset/id.go @@ -0,0 +1,24 @@ +package dataset + +import "github.com/reearth/reearth-backend/pkg/id" + +type ID = id.DatasetID +type IDSet = id.DatasetIDSet + +type SchemaID = id.DatasetSchemaID +type SchemaIDSet = id.DatasetSchemaIDSet + +type FieldID = id.DatasetSchemaFieldID +type FieldIDSet = id.DatasetSchemaFieldIDSet + +var NewID = id.NewDatasetID +var NewSchemaID = id.NewDatasetSchemaID +var NewFieldID = id.NewDatasetSchemaFieldID + +var MustID = id.MustDatasetID +var MustSchemaID = id.MustDatasetSchemaID +var MustFieldID = id.MustDatasetSchemaFieldID + +var IDFrom = id.DatasetIDFrom +var SchemaIDFrom = id.DatasetSchemaIDFrom +var FieldIDFrom = id.DatasetSchemaFieldIDFrom diff --git a/pkg/dataset/loader.go b/pkg/dataset/loader.go index 5092aa34..813d209f 100644 --- a/pkg/dataset/loader.go +++ b/pkg/dataset/loader.go @@ -41,3 +41,22 @@ func LoaderFromMap(data map[id.DatasetID]*Dataset) Loader { return res, nil } } + +func (l Loader) FindByPointer(ctx context.Context, p *Pointer) (*Dataset, *Field, error) { + if l == nil { + return nil, nil, nil + } + pd := p.Dataset() + if pd == nil { + return nil, nil, nil + } + d, err := l(ctx, *p.Dataset()) + if err != nil { + return nil, nil, err + } + df := d.First() + if df == nil { + return nil, nil, nil + } + return df, df.FieldByPointer(p), nil +} diff --git a/pkg/dataset/migrator.go b/pkg/dataset/migrator.go new file mode 100644 index 00000000..4e5bb00a --- /dev/null +++ b/pkg/dataset/migrator.go @@ -0,0 +1,113 @@ +package dataset + +import "context" + +type Migrator struct { + d func(ID) *ID + s func(SchemaID) *SchemaID + f func(FieldID) *FieldID +} + +func NewMigrator(d func(ID) *ID, s func(SchemaID) *SchemaID, f func(FieldID) *FieldID) *Migrator { + if d == nil || s == nil || f == nil { + return nil + } + return &Migrator{d: d, s: s, f: f} +} + +func MigratorFrom(d map[ID]ID, s map[SchemaID]SchemaID, f map[FieldID]FieldID) *Migrator { + df := func(i ID) *ID { + f, ok := d[i] + if !ok { + return nil + } + return f.Ref() + } + sf := func(i SchemaID) *SchemaID { + f, ok := s[i] + if !ok { + return nil + } + return f.CopyRef() + } + ff := func(i FieldID) *FieldID { + f, ok := f[i] + if !ok { + return nil + } + return f.CopyRef() + } + return &Migrator{d: df, s: sf, f: ff} +} + +func (m *Migrator) MigrateAndValidateGraphPointer(ctx context.Context, p *GraphPointer, l GraphLoader) (*GraphPointer, error) { + if m == nil || p == nil { + return nil, nil + } + + np := m.MigrateGraphPointer(p) + d, f, err := l.ByGraphPointer(ctx, np) + if err != nil || d == nil || f == nil { + return nil, err + } + + return np, nil +} + +func (m *Migrator) MigrateGraphPointer(p *GraphPointer) *GraphPointer { + if m == nil || p == nil { + return nil + } + + pointers := p.Pointers() + pointers2 := make([]*Pointer, 0, len(pointers)) + for _, p := range pointers { + pointers2 = append(pointers2, m.MigratePointer(p)) + } + return NewGraphPointer(pointers2) +} + +func (m *Migrator) MigratePointer(p *Pointer) *Pointer { + if m == nil || p == nil { + return nil + } + + ns := m.getS(p.Schema()) + nf := m.getF(p.Field()) + + if d := p.Dataset(); d != nil { + return PointAt(m.getD(*d), ns, nf) + } + + return PointAtField(ns, nf) +} + +func (m *Migrator) getD(d ID) ID { + if m == nil || m.d == nil { + return d + } + if nd := m.d(d); nd != nil { + return *nd + } + return d +} + +func (m *Migrator) getS(s SchemaID) SchemaID { + if m == nil || m.s == nil { + return s + } + if ns := m.s(s); ns != nil { + return *ns + } + return s +} + +func (m *Migrator) getF(f FieldID) FieldID { + if m == nil || m.f == nil { + return f + } + if nf := m.f(f); nf != nil { + return *nf + } + return f +} diff --git a/pkg/dataset/migrator_test.go b/pkg/dataset/migrator_test.go new file mode 100644 index 00000000..a01a54de --- /dev/null +++ b/pkg/dataset/migrator_test.go @@ -0,0 +1,620 @@ +package dataset + +import ( + "context" + "testing" + + "github.com/reearth/reearth-backend/pkg/id" + "github.com/stretchr/testify/assert" +) + +func TestNewMigrator(t *testing.T) { + di := NewID() + si := NewSchemaID() + fi := NewFieldID() + d := func(ID) *ID { return &di } + s := func(SchemaID) *SchemaID { return &si } + f := func(FieldID) *FieldID { return &fi } + + type args struct { + d func(ID) *ID + s func(SchemaID) *SchemaID + f func(FieldID) *FieldID + } + tests := []struct { + name string + args args + wantnil bool + }{ + { + name: "ok", + args: args{d: d, s: s, f: f}, + wantnil: false, + }, + { + name: "nil", + args: args{d: nil, s: s, f: f}, + wantnil: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := NewMigrator(tt.args.d, tt.args.s, tt.args.f) + if !tt.wantnil { + assert.Equal(t, tt.args.d(ID{}), m.d(ID{})) + assert.Equal(t, tt.args.s(SchemaID{}), m.s(SchemaID{})) + assert.Equal(t, tt.args.f(FieldID{}), m.f(FieldID{})) + } else { + assert.Nil(t, m) + } + }) + } +} + +func TestMigratorFrom(t *testing.T) { + d1 := NewID() + d2 := NewID() + s1 := NewSchemaID() + s2 := NewSchemaID() + f1 := NewFieldID() + f2 := NewFieldID() + d := map[ID]ID{d1: d2} + s := map[SchemaID]SchemaID{s1: s2} + f := map[FieldID]FieldID{f1: f2} + + type args struct { + d map[ID]ID + s map[SchemaID]SchemaID + f map[FieldID]FieldID + } + tests := []struct { + name string + args args + }{ + { + name: "ok", + args: args{d: d, s: s, f: f}, + }, + { + name: "partial nil", + args: args{d: d, s: nil, f: nil}, + }, + { + name: "nil", + args: args{d: nil, s: nil, f: nil}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := MigratorFrom(tt.args.d, tt.args.s, tt.args.f) + if r, ok := tt.args.d[d1]; ok { + assert.Equal(t, &r, res.d(d1)) + } else { + assert.Nil(t, res.d(d1)) + } + if r, ok := tt.args.s[s1]; ok { + assert.Equal(t, &r, res.s(s1)) + } else { + assert.Nil(t, res.s(s1)) + } + if r, ok := tt.args.f[f1]; ok { + assert.Equal(t, &r, res.f(f1)) + } else { + assert.Nil(t, res.f(f1)) + } + assert.Nil(t, res.d(d2)) + assert.Nil(t, res.s(s2)) + assert.Nil(t, res.f(f2)) + }) + } +} + +func TestMigrator_MigrateAndValidateGraphPointer(t *testing.T) { + d1 := NewID() + d2 := NewID() + s1 := NewSchemaID() + s2 := NewSchemaID() + f1 := NewFieldID() + f2 := NewFieldID() + d := func(i ID) *ID { + if i == d1 { + return &d2 + } + return &i + } + s := func(i SchemaID) *SchemaID { + if i == s1 { + return &s2 + } + return &i + } + f := func(i FieldID) *FieldID { + if i == f1 { + return &f2 + } + return &i + } + l := GraphLoaderFromMap(Map{ + d2: New().ID(d2).Schema(s2).Scene(id.NewSceneID()).Fields([]*Field{ + NewField(f2, ValueTypeString.ValueFrom("foo"), ""), + }).MustBuild(), + }) + + type args struct { + ctx context.Context + p *GraphPointer + l GraphLoader + } + tests := []struct { + name string + target *Migrator + args args + want *GraphPointer + wantErr error + }{ + { + name: "ok", + target: &Migrator{d: d, s: s, f: f}, + args: args{ + ctx: context.Background(), + p: &GraphPointer{ + pointers: []*Pointer{ + {dataset: &d1, schema: s1, field: f1}, + }, + }, + l: l, + }, + want: &GraphPointer{ + pointers: []*Pointer{ + {dataset: &d2, schema: s2, field: f2}, + }, + }, + wantErr: nil, + }, + { + name: "invalid", + target: &Migrator{d: nil, s: s, f: f}, + args: args{ + ctx: context.Background(), + p: &GraphPointer{ + pointers: []*Pointer{ + {dataset: &d1, schema: s1, field: f1}, + }, + }, + l: l, + }, + want: nil, + wantErr: nil, + }, + { + name: "nil pointer", + target: &Migrator{d: d, s: s, f: f}, + args: args{ + ctx: context.Background(), + p: nil, + l: l, + }, + want: nil, + wantErr: nil, + }, + { + name: "empty", + target: &Migrator{}, + args: args{ + ctx: context.Background(), + p: &GraphPointer{ + pointers: []*Pointer{ + {dataset: &d1, schema: s1, field: f1}, + }, + }, + l: l, + }, + want: nil, + wantErr: nil, + }, + { + name: "nil", + target: nil, + args: args{ + ctx: context.Background(), + p: &GraphPointer{ + pointers: []*Pointer{ + {dataset: &d1, schema: s1, field: f1}, + {dataset: nil, schema: s2, field: f1}, + }, + }, + l: l, + }, + want: nil, + wantErr: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.target.MigrateAndValidateGraphPointer(tt.args.ctx, tt.args.p, tt.args.l) + if tt.wantErr == nil { + assert.NoError(t, err) + } else { + assert.Equal(t, tt.wantErr, err) + } + assert.Equal(t, tt.want, got) + }) + } +} + +func TestMigrator_MigrateGraphPointer(t *testing.T) { + d1 := NewID() + d2 := NewID() + s1 := NewSchemaID() + s2 := NewSchemaID() + f1 := NewFieldID() + f2 := NewFieldID() + d := func(i ID) *ID { + if i == d1 { + return &d2 + } + return &i + } + s := func(i SchemaID) *SchemaID { + if i == s1 { + return &s2 + } + return &i + } + f := func(i FieldID) *FieldID { + if i == f1 { + return &f2 + } + return &i + } + + type args struct { + p *GraphPointer + } + tests := []struct { + name string + target *Migrator + args args + want *GraphPointer + }{ + { + name: "ok", + target: &Migrator{d: d, s: s, f: f}, + args: args{ + p: &GraphPointer{ + pointers: []*Pointer{ + {dataset: &d1, schema: s1, field: f1}, + {dataset: nil, schema: s2, field: f1}, + }, + }, + }, + want: &GraphPointer{ + pointers: []*Pointer{ + {dataset: &d2, schema: s2, field: f2}, + {dataset: nil, schema: s2, field: f2}, + }, + }, + }, + { + name: "nil pointer", + target: &Migrator{d: d, s: s, f: f}, + args: args{ + p: nil, + }, + want: nil, + }, + { + name: "empty", + target: &Migrator{}, + args: args{ + p: &GraphPointer{ + pointers: []*Pointer{ + {dataset: &d1, schema: s1, field: f1}, + {dataset: nil, schema: s2, field: f1}, + }, + }, + }, + want: &GraphPointer{ + pointers: []*Pointer{ + {dataset: &d1, schema: s1, field: f1}, + {dataset: nil, schema: s2, field: f1}, + }, + }, + }, + { + name: "nil", + target: nil, + args: args{ + p: &GraphPointer{ + pointers: []*Pointer{ + {dataset: &d1, schema: s1, field: f1}, + {dataset: nil, schema: s2, field: f1}, + }, + }, + }, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.target.MigrateGraphPointer(tt.args.p) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestMigrator_MigratePointer(t *testing.T) { + d1 := NewID() + d2 := NewID() + s1 := NewSchemaID() + s2 := NewSchemaID() + f1 := NewFieldID() + f2 := NewFieldID() + d := func(i ID) *ID { + if i == d1 { + return &d2 + } + return &i + } + s := func(i SchemaID) *SchemaID { + if i == s1 { + return &s2 + } + return &i + } + f := func(i FieldID) *FieldID { + if i == f1 { + return &f2 + } + return &i + } + + type args struct { + p *Pointer + } + tests := []struct { + name string + target *Migrator + args args + want *Pointer + }{ + { + name: "ok", + target: &Migrator{d: d, s: s, f: f}, + args: args{ + p: &Pointer{ + dataset: &d1, + schema: s1, + field: f1, + }, + }, + want: &Pointer{ + dataset: &d2, + schema: s2, + field: f2, + }, + }, + { + name: "partial", + target: &Migrator{d: d, s: s, f: f}, + args: args{ + p: &Pointer{ + dataset: nil, + schema: s2, + field: f1, + }, + }, + want: &Pointer{ + dataset: nil, + schema: s2, + field: f2, + }, + }, + { + name: "nil pointer", + target: &Migrator{d: d, s: s, f: f}, + args: args{ + p: nil, + }, + want: nil, + }, + { + name: "empty", + target: &Migrator{}, + args: args{ + p: &Pointer{ + dataset: &d1, + schema: s1, + field: f1, + }, + }, + want: &Pointer{ + dataset: &d1, + schema: s1, + field: f1, + }, + }, + { + name: "nil", + target: nil, + args: args{ + p: &Pointer{ + dataset: &d1, + schema: s1, + field: f1, + }, + }, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.target.MigratePointer(tt.args.p) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestMigrator_getD(t *testing.T) { + d1 := NewID() + d2 := NewID() + d := func(i ID) *ID { + if i == d1 { + return &d2 + } + return &i + } + + type args struct { + d ID + } + tests := []struct { + name string + target *Migrator + args args + want ID + }{ + { + name: "found", + target: &Migrator{d: d}, + args: args{d: d1}, + want: d2, + }, + { + name: "not found", + target: &Migrator{d: d}, + args: args{d: d2}, + want: d2, + }, + { + name: "empty", + target: &Migrator{}, + args: args{d: d1}, + want: d1, + }, + { + name: "nil", + target: nil, + args: args{d: d1}, + want: d1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.target.getD(tt.args.d) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestMigrator_getS(t *testing.T) { + s1 := NewSchemaID() + s2 := NewSchemaID() + s := func(i SchemaID) *SchemaID { + if i == s1 { + return &s2 + } + return &i + } + + type args struct { + s SchemaID + } + tests := []struct { + name string + target *Migrator + args args + want SchemaID + }{ + { + name: "found", + target: &Migrator{s: s}, + args: args{s: s1}, + want: s2, + }, + { + name: "not found", + target: &Migrator{s: s}, + args: args{s: s2}, + want: s2, + }, + { + name: "empty", + target: &Migrator{}, + args: args{s: s1}, + want: s1, + }, + { + name: "nil", + target: nil, + args: args{s: s1}, + want: s1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.target.getS(tt.args.s) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestMigrator_getF(t *testing.T) { + f1 := NewFieldID() + f2 := NewFieldID() + f := func(i FieldID) *FieldID { + if i == f1 { + return &f2 + } + return &i + } + + type args struct { + f FieldID + } + tests := []struct { + name string + target *Migrator + args args + want FieldID + }{ + { + name: "found", + target: &Migrator{f: f}, + args: args{f: f1}, + want: f2, + }, + { + name: "not found", + target: &Migrator{f: f}, + args: args{f: f2}, + want: f2, + }, + { + name: "empty", + target: &Migrator{}, + args: args{f: f1}, + want: f1, + }, + { + name: "nil", + target: nil, + args: args{f: f1}, + want: f1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.target.getF(tt.args.f) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/pkg/dataset/pointer.go b/pkg/dataset/pointer.go new file mode 100644 index 00000000..a1d9803a --- /dev/null +++ b/pkg/dataset/pointer.go @@ -0,0 +1,76 @@ +package dataset + +type Pointer struct { + dataset *ID + schema SchemaID + field FieldID +} + +func PointAt(d ID, s SchemaID, f FieldID) *Pointer { + if d.IsNil() || s.IsNil() || f.IsNil() { + return nil + } + return &Pointer{ + dataset: d.CopyRef(), + schema: s, + field: f, + } +} + +func PointAtField(s SchemaID, f FieldID) *Pointer { + if s.IsNil() || f.IsNil() { + return nil + } + return &Pointer{ + schema: s, + field: f, + } +} + +func (p *Pointer) Dataset() *ID { + if p == nil { + return nil + } + return p.dataset.CopyRef() +} + +func (p *Pointer) Schema() SchemaID { + if p == nil { + return SchemaID{} + } + return p.schema +} + +func (p *Pointer) Field() FieldID { + if p == nil { + return FieldID{} + } + return p.field +} + +func (p *Pointer) IsEmpty() bool { + return p == nil || p.field.IsNil() || p.schema.IsNil() +} + +func (l *Pointer) Clone() *Pointer { + if l == nil || l.IsEmpty() { + return nil + } + return &Pointer{ + dataset: l.Dataset(), + schema: l.Schema(), + field: l.Field(), + } +} + +func (l *Pointer) PointAt(d *ID) *Pointer { + if l == nil || l.IsEmpty() { + return nil + } + + return &Pointer{ + dataset: d.CopyRef(), + schema: l.Schema(), + field: l.Field(), + } +} diff --git a/pkg/dataset/pointer_test.go b/pkg/dataset/pointer_test.go new file mode 100644 index 00000000..ab089e6a --- /dev/null +++ b/pkg/dataset/pointer_test.go @@ -0,0 +1,364 @@ +package dataset + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPointAt(t *testing.T) { + d := NewID() + s := NewSchemaID() + f := NewFieldID() + + type args struct { + d ID + s SchemaID + f FieldID + } + tests := []struct { + name string + args args + want *Pointer + }{ + { + name: "ok", + args: args{ + d: d, + s: s, + f: f, + }, + want: &Pointer{ + dataset: &d, + schema: s, + field: f, + }, + }, + { + name: "empty", + args: args{ + d: ID{}, + s: SchemaID{}, + f: FieldID{}, + }, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, PointAt(tt.args.d, tt.args.s, tt.args.f)) + }) + } +} + +func TestPointAtField(t *testing.T) { + s := NewSchemaID() + f := NewFieldID() + + type args struct { + s SchemaID + f FieldID + } + tests := []struct { + name string + args args + want *Pointer + }{ + { + name: "ok", + args: args{ + s: s, + f: f, + }, + want: &Pointer{ + dataset: nil, + schema: s, + field: f, + }, + }, + { + name: "empty", + args: args{ + s: SchemaID{}, + f: FieldID{}, + }, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, PointAtField(tt.args.s, tt.args.f)) + }) + } +} + +func TestPointer_Dataset(t *testing.T) { + d := NewID() + + tests := []struct { + name string + target *Pointer + want *ID + }{ + { + name: "ok", + target: &Pointer{ + dataset: &d, + }, + want: &d, + }, + { + name: "empty", + target: &Pointer{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Dataset()) + }) + } +} + +func TestPointer_Schema(t *testing.T) { + s := NewSchemaID() + + tests := []struct { + name string + target *Pointer + want SchemaID + }{ + { + name: "ok", + target: &Pointer{ + schema: s, + }, + want: s, + }, + { + name: "empty", + target: &Pointer{}, + want: SchemaID{}, + }, + { + name: "nil", + target: nil, + want: SchemaID{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Schema()) + }) + } +} + +func TestPointer_Field(t *testing.T) { + f := NewFieldID() + + tests := []struct { + name string + target *Pointer + want FieldID + }{ + { + name: "ok", + target: &Pointer{ + field: f, + }, + want: f, + }, + { + name: "empty", + target: &Pointer{}, + want: FieldID{}, + }, + { + name: "nil", + target: nil, + want: FieldID{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Field()) + }) + } +} + +func TestPointer_IsEmpty(t *testing.T) { + tests := []struct { + name string + target *Pointer + want bool + }{ + { + name: "empty", + target: &Pointer{}, + want: true, + }, + { + name: "nil", + target: nil, + want: true, + }, + { + name: "not empty", + target: &Pointer{ + schema: NewSchemaID(), + field: NewFieldID(), + }, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.IsEmpty()) + }) + } +} + +func TestPointer_Clone(t *testing.T) { + d := NewID() + s := NewSchemaID() + f := NewFieldID() + + tests := []struct { + name string + target *Pointer + want *Pointer + }{ + { + name: "ok", + target: &Pointer{ + dataset: &d, + schema: s, + field: f, + }, + want: &Pointer{ + dataset: &d, + schema: s, + field: f, + }, + }, + { + name: "empty", + target: &Pointer{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := tt.target.Clone() + assert.Equal(t, tt.want, res) + if tt.want != nil { + assert.NotSame(t, tt.want, res) + } + }) + } +} + +func TestPointer_PointAt(t *testing.T) { + d := NewID() + d2 := NewID() + s := NewSchemaID() + f := NewFieldID() + + type args struct { + d *ID + } + tests := []struct { + name string + target *Pointer + args args + want *Pointer + }{ + { + name: "ok1", + target: &Pointer{ + dataset: nil, + schema: s, + field: f, + }, + args: args{ + d: &d, + }, + want: &Pointer{ + dataset: &d, + schema: s, + field: f, + }, + }, + { + name: "ok2", + target: &Pointer{ + dataset: &d, + schema: s, + field: f, + }, + args: args{ + d: &d2, + }, + want: &Pointer{ + dataset: &d2, + schema: s, + field: f, + }, + }, + { + name: "ok3", + target: &Pointer{ + dataset: &d, + schema: s, + field: f, + }, + args: args{ + d: nil, + }, + want: &Pointer{ + dataset: nil, + schema: s, + field: f, + }, + }, + { + name: "empty", + target: &Pointer{}, + args: args{ + d: &d, + }, + want: nil, + }, + { + name: "nil", + args: args{ + d: &d, + }, + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.PointAt(tt.args.d)) + }) + } +} diff --git a/pkg/dataset/schema.go b/pkg/dataset/schema.go index ae3bf22a..3f7507ae 100644 --- a/pkg/dataset/schema.go +++ b/pkg/dataset/schema.go @@ -111,12 +111,17 @@ func (d *Schema) FieldByType(t ValueType) *SchemaField { return nil } -// Dynamic _ +func (d *Schema) FieldByPointer(p *Pointer) *SchemaField { + if d == nil || p.IsEmpty() || d.ID() != p.Schema() { + return nil + } + return d.Field(p.Field()) +} + func (d *Schema) Dynamic() bool { return d.dynamic } -// Rename _ func (u *Schema) Rename(name string) { u.name = name } From b5e65268e1283957355d8b2973d35042ae9a0844 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Thu, 2 Dec 2021 17:08:29 +0900 Subject: [PATCH 04/55] fix dataset --- pkg/dataset/diff.go | 93 ++++++++++++++++++++++++++++++- pkg/dataset/graph_loader.go | 5 ++ pkg/dataset/graph_pointer.go | 7 ++- pkg/dataset/graph_pointer_test.go | 20 ++++++- pkg/dataset/id.go | 4 ++ pkg/dataset/schema_list.go | 14 +++-- 6 files changed, 130 insertions(+), 13 deletions(-) diff --git a/pkg/dataset/diff.go b/pkg/dataset/diff.go index bbd41a72..61c9223f 100644 --- a/pkg/dataset/diff.go +++ b/pkg/dataset/diff.go @@ -2,9 +2,98 @@ package dataset import "github.com/reearth/reearth-backend/pkg/id" -// Diff _ type Diff struct { Added List Removed List - Others map[id.DatasetID]*Dataset + Others Map +} + +type MigrationMap struct { + Datasets map[ID]ID + Schemas map[SchemaID]SchemaID + Fields map[FieldID]FieldID + SchemaRev map[SchemaID]SchemaID + OldDatasets Map + OldSchemas SchemaMap + Deleted *IDSet + DeletedSchemas *SchemaIDSet + Diff map[SchemaID]Diff +} + +func NewMigrationMap(newdsl SchemaList, newdl List, getOldSchemas func(*Schema) (SchemaList, error), getDatasets func(*Schema) (List, error)) (MigrationMap, error) { + deleted := NewIDSet() + deletedSchemas := NewSchemaIDDset() + + datasetMapOldNew := map[id.DatasetID]id.DatasetID{} + schemaMapOldNew := map[id.DatasetSchemaID]id.DatasetSchemaID{} + schemaMapNewOld := map[id.DatasetSchemaID]id.DatasetSchemaID{} + schemaFieldMap := map[id.DatasetSchemaFieldID]id.DatasetSchemaFieldID{} + oldSchemaMap := map[id.DatasetSchemaID]*Schema{} + diffMap := map[id.DatasetSchemaID]Diff{} + + for _, newds := range newdsl { + olddsl, err := getOldSchemas(newds) + if err != nil { + return MigrationMap{}, err + } + oldds := olddsl.Find(func(s *Schema) bool { + return s.ID() != newds.ID() + }) + if oldds == nil { + continue + } + + oldSchemaMap[oldds.ID()] = oldds + schemaMapNewOld[newds.ID()] = oldds.ID() + schemaMapOldNew[oldds.ID()] = newds.ID() + + fieldDiff := oldds.FieldDiffBySource(newds) + for of, f := range fieldDiff.Replaced { + schemaFieldMap[of] = f.ID() + } + + olddl, err := getDatasets(oldds) + if err != nil { + return MigrationMap{}, err + } + + deletedSchemas.Add(oldds.ID()) + for _, oldd := range olddl { + deleted.Add(oldd.ID()) + } + + currentNewdl := newdl.FilterByDatasetSchema(newds.ID()) + diff := List(olddl).DiffBySource(currentNewdl) + diffMap[newds.ID()] = diff + for od, d := range diff.Others { + datasetMapOldNew[od] = d.ID() + } + } + + return MigrationMap{ + Datasets: datasetMapOldNew, + Schemas: schemaMapOldNew, + Fields: schemaFieldMap, + SchemaRev: schemaMapNewOld, + OldSchemas: oldSchemaMap, + Deleted: deleted, + DeletedSchemas: deletedSchemas, + Diff: diffMap, + }, nil +} + +func (mm MigrationMap) OldSchema(newsid SchemaID) *Schema { + oldsid, ok := mm.SchemaRev[newsid] + if !ok { + return nil + } + oldds, ok := mm.OldSchemas[oldsid] + if !ok { + return nil + } + return oldds +} + +func (mm MigrationMap) Migrator() *Migrator { + return MigratorFrom(mm.Datasets, mm.Schemas, mm.Fields) } diff --git a/pkg/dataset/graph_loader.go b/pkg/dataset/graph_loader.go index ee312476..4c7cd88e 100644 --- a/pkg/dataset/graph_loader.go +++ b/pkg/dataset/graph_loader.go @@ -37,6 +37,11 @@ func GraphLoaderFromMapAndGraph(m Map, g GraphLoader) GraphLoader { } func (l GraphLoader) ByGraphPointer(ctx context.Context, p *GraphPointer) (List, *Field, error) { + if p.IsLinkedFully() { + last := p.Last() + return l(ctx, *last.Dataset(), last.Field()) + } + d := p.First().Dataset() if d == nil { return nil, nil, nil diff --git a/pkg/dataset/graph_pointer.go b/pkg/dataset/graph_pointer.go index f728ee9e..40cc108c 100644 --- a/pkg/dataset/graph_pointer.go +++ b/pkg/dataset/graph_pointer.go @@ -5,7 +5,7 @@ type GraphPointer struct { } func NewGraphPointer(p []*Pointer) *GraphPointer { - if len(p) == 0 || p[0].Dataset() == nil { + if len(p) == 0 { return nil } pointers := make([]*Pointer, 0, len(p)) @@ -35,8 +35,9 @@ func (l *GraphPointer) WithDataset(ds ID) *GraphPointer { } links := l.Clone() - first := l.First() - links.pointers[0] = first.PointAt(&ds) + if links.First().Dataset() == nil { + links.pointers[0] = links.pointers[0].PointAt(&ds) + } return links } diff --git a/pkg/dataset/graph_pointer_test.go b/pkg/dataset/graph_pointer_test.go index 8646f73a..09b85679 100644 --- a/pkg/dataset/graph_pointer_test.go +++ b/pkg/dataset/graph_pointer_test.go @@ -29,11 +29,13 @@ func TestNewGraphPointer(t *testing.T) { }, }, { - name: "invalid", + name: "ok2", args: args{ p: []*Pointer{PointAtField(s, f)}, }, - want: nil, + want: &GraphPointer{ + []*Pointer{PointAtField(s, f)}, + }, }, { name: "empty", @@ -117,6 +119,18 @@ func TestGraphPointer_WithDataset(t *testing.T) { }{ { name: "ok", + target: &GraphPointer{ + []*Pointer{PointAtField(s, f), PointAt(d, s, f)}, + }, + args: args{ + ds: d, + }, + want: &GraphPointer{ + []*Pointer{PointAt(d, s, f), PointAt(d, s, f)}, + }, + }, + { + name: "not changed", target: &GraphPointer{ []*Pointer{PointAt(d, s, f), PointAt(d, s, f)}, }, @@ -124,7 +138,7 @@ func TestGraphPointer_WithDataset(t *testing.T) { ds: d2, }, want: &GraphPointer{ - []*Pointer{PointAt(d2, s, f), PointAt(d, s, f)}, + []*Pointer{PointAt(d, s, f), PointAt(d, s, f)}, }, }, { diff --git a/pkg/dataset/id.go b/pkg/dataset/id.go index 781edc77..890a579b 100644 --- a/pkg/dataset/id.go +++ b/pkg/dataset/id.go @@ -22,3 +22,7 @@ var MustFieldID = id.MustDatasetSchemaFieldID var IDFrom = id.DatasetIDFrom var SchemaIDFrom = id.DatasetSchemaIDFrom var FieldIDFrom = id.DatasetSchemaFieldIDFrom + +var NewIDSet = id.NewDatasetIDSet +var NewSchemaIDDset = id.NewDatasetSchemaIDSet +var NewFieldIDDset = id.NewDatasetSchemaFieldIDSet diff --git a/pkg/dataset/schema_list.go b/pkg/dataset/schema_list.go index 6e55b026..86358af4 100644 --- a/pkg/dataset/schema_list.go +++ b/pkg/dataset/schema_list.go @@ -2,10 +2,8 @@ package dataset import "github.com/reearth/reearth-backend/pkg/id" -// SchemaList _ type SchemaList []*Schema -// Map _ func (dsl SchemaList) Map() SchemaMap { if dsl == nil { return nil @@ -19,10 +17,17 @@ func (dsl SchemaList) Map() SchemaMap { return m } -// SchemaMap _ +func (dsl SchemaList) Find(fn func(s *Schema) bool) *Schema { + for _, s := range dsl { + if fn(s) { + return s + } + } + return nil +} + type SchemaMap map[id.DatasetSchemaID]*Schema -// Slice _ func (dsm SchemaMap) Slice() SchemaList { if dsm == nil { return nil @@ -36,7 +41,6 @@ func (dsm SchemaMap) Slice() SchemaList { return res } -// GraphSearchByFields _ func (dsm SchemaMap) GraphSearchByFields(root id.DatasetSchemaID, fields ...id.DatasetSchemaFieldID) (SchemaList, *SchemaField) { res := make(SchemaList, 0, len(fields)) currentDs := dsm[root] From 0c760d2bbf89c2965c765da2a42ee9d40fd18ef8 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Thu, 2 Dec 2021 17:09:43 +0900 Subject: [PATCH 05/55] use dataset.GraphPointer as property link --- .../adapter/gql/gqlmodel/convert_property.go | 23 +- .../infrastructure/mongo/mongodoc/property.go | 19 +- internal/usecase/interactor/property.go | 11 +- internal/usecase/interfaces/property.go | 3 +- pkg/layer/merged_test.go | 422 ++++++++------- pkg/property/field.go | 81 +-- pkg/property/field_builder.go | 9 +- pkg/property/field_builder_test.go | 55 +- pkg/property/field_test.go | 36 +- pkg/property/group.go | 20 +- pkg/property/group_list.go | 39 -- pkg/property/group_list_test.go | 9 +- pkg/property/group_test.go | 17 +- pkg/property/initializer.go | 13 +- pkg/property/initializer_test.go | 5 +- pkg/property/item.go | 1 - pkg/property/link.go | 443 ---------------- pkg/property/link_test.go | 481 ------------------ pkg/property/merged.go | 27 +- pkg/property/merged_test.go | 95 +++- pkg/property/migrator.go | 72 +++ pkg/property/property.go | 14 +- pkg/property/property_test.go | 8 +- pkg/property/sealed.go | 12 +- pkg/property/sealed_test.go | 8 +- pkg/property/value_dataset.go | 3 +- pkg/scene/builder/builder_test.go | 30 +- pkg/scene/sceneops/dataset_migrator.go | 119 +---- 28 files changed, 572 insertions(+), 1503 deletions(-) delete mode 100644 pkg/property/link.go delete mode 100644 pkg/property/link_test.go diff --git a/internal/adapter/gql/gqlmodel/convert_property.go b/internal/adapter/gql/gqlmodel/convert_property.go index ce36a8ad..8723d97c 100644 --- a/internal/adapter/gql/gqlmodel/convert_property.go +++ b/internal/adapter/gql/gqlmodel/convert_property.go @@ -3,6 +3,7 @@ package gqlmodel import ( "strings" + "github.com/reearth/reearth-backend/pkg/dataset" "github.com/reearth/reearth-backend/pkg/id" "github.com/reearth/reearth-backend/pkg/property" "github.com/reearth/reearth-backend/pkg/value" @@ -122,7 +123,7 @@ func ToPropertyField(f *property.Field, parent *property.Property, gl *property. var links []*PropertyFieldLink if flinks := f.Links(); flinks != nil { links = make([]*PropertyFieldLink, 0, flinks.Len()) - for _, l := range flinks.Links() { + for _, l := range flinks.Pointers() { links = append(links, ToPropertyFieldLink(l)) } } @@ -138,24 +139,24 @@ func ToPropertyField(f *property.Field, parent *property.Property, gl *property. } } -func ToPropertyFieldLinks(flinks *property.Links) []*PropertyFieldLink { +func ToPropertyFieldLinks(flinks *dataset.GraphPointer) []*PropertyFieldLink { if flinks == nil { return nil } var links []*PropertyFieldLink links = make([]*PropertyFieldLink, 0, flinks.Len()) - for _, l := range flinks.Links() { + for _, l := range flinks.Pointers() { links = append(links, ToPropertyFieldLink(l)) } return links } -func FromPropertyFieldLink(datasetSchema, ds, fields []*id.ID) *property.Links { +func FromPropertyFieldLink(datasetSchema, ds, fields []*id.ID) *dataset.GraphPointer { if len(datasetSchema) != len(fields) || (ds != nil && len(ds) != len(fields) && len(ds) > 1) { return nil } - links := make([]*property.Link, 0, len(datasetSchema)) + links := make([]*dataset.Pointer, 0, len(datasetSchema)) for i, dss := range datasetSchema { f := fields[i] if dss == nil || f == nil { @@ -164,24 +165,24 @@ func FromPropertyFieldLink(datasetSchema, ds, fields []*id.ID) *property.Links { dsid := id.DatasetSchemaID(*dss) dsfid := id.DatasetSchemaFieldID(*f) if len(ds) == 0 || (len(ds) == 1 && i > 0) { - links = append(links, property.NewLinkFieldOnly(dsid, dsfid)) + links = append(links, dataset.PointAtField(dsid, dsfid)) } else { d := ds[i] if d == nil { return nil } - links = append(links, property.NewLink(id.DatasetID(*d), dsid, dsfid)) + links = append(links, dataset.PointAt(id.DatasetID(*d), dsid, dsfid)) } } - return property.NewLinks(links) + return dataset.NewGraphPointer(links) } -func ToPropertyFieldLink(link *property.Link) *PropertyFieldLink { +func ToPropertyFieldLink(link *dataset.Pointer) *PropertyFieldLink { return &PropertyFieldLink{ DatasetID: link.Dataset().IDRef(), - DatasetSchemaID: link.DatasetSchema().ID(), - DatasetSchemaFieldID: link.DatasetSchemaField().ID(), + DatasetSchemaID: link.Schema().ID(), + DatasetSchemaFieldID: link.Field().ID(), } } diff --git a/internal/infrastructure/mongo/mongodoc/property.go b/internal/infrastructure/mongo/mongodoc/property.go index 3e962bac..8e332634 100644 --- a/internal/infrastructure/mongo/mongodoc/property.go +++ b/internal/infrastructure/mongo/mongodoc/property.go @@ -3,6 +3,7 @@ package mongodoc import ( "go.mongodb.org/mongo-driver/bson" + "github.com/reearth/reearth-backend/pkg/dataset" "github.com/reearth/reearth-backend/pkg/id" "github.com/reearth/reearth-backend/pkg/property" ) @@ -107,13 +108,13 @@ func newPropertyField(f *property.Field) *PropertyFieldDocument { Value: f.Value().Interface(), } - if links := f.Links().Links(); links != nil { + if links := f.Links().Pointers(); links != nil { field.Links = make([]*PropertyLinkDocument, 0, len(links)) for _, l := range links { field.Links = append(field.Links, &PropertyLinkDocument{ - Schema: l.DatasetSchema().StringRef(), + Schema: l.Schema().RefString(), Dataset: l.Dataset().StringRef(), - Field: l.DatasetSchemaField().StringRef(), + Field: l.Field().RefString(), }) } } @@ -198,24 +199,24 @@ func toModelPropertyField(f *PropertyFieldDocument) *property.Field { return nil } - var flinks *property.Links + var flinks *dataset.GraphPointer if f.Links != nil { - links := make([]*property.Link, 0, len(f.Links)) + links := make([]*dataset.Pointer, 0, len(f.Links)) for _, l := range f.Links { - var link *property.Link + var link *dataset.Pointer d := id.DatasetIDFromRef(l.Dataset) ds := id.DatasetSchemaIDFromRef(l.Schema) df := id.DatasetSchemaFieldIDFromRef(l.Field) if d != nil && ds != nil && df != nil { - link = property.NewLink(*d, *ds, *df) + link = dataset.PointAt(*d, *ds, *df) } else if ds != nil && df != nil { - link = property.NewLinkFieldOnly(*ds, *df) + link = dataset.PointAtField(*ds, *df) } else { continue } links = append(links, link) } - flinks = property.NewLinks(links) + flinks = dataset.NewGraphPointer(links) } vt := property.ValueType(f.Type) diff --git a/internal/usecase/interactor/property.go b/internal/usecase/interactor/property.go index ad480908..5b9f1ea5 100644 --- a/internal/usecase/interactor/property.go +++ b/internal/usecase/interactor/property.go @@ -291,17 +291,12 @@ func (i *Property) LinkValue(ctx context.Context, inp interfaces.LinkPropertyVal propertyScenes := []id.SceneID{p.Scene()} if inp.Links != nil { - dsids := inp.Links.DatasetSchemaIDs() - dids := inp.Links.DatasetIDs() - dss, err := i.datasetSchemaRepo.FindByIDs(ctx, dsids, propertyScenes) + ds, err := i.datasetRepo.FindByIDs(ctx, inp.Links.Datasets(), propertyScenes) if err != nil { return nil, nil, nil, nil, err } - ds, err := i.datasetRepo.FindByIDs(ctx, dids, propertyScenes) - if err != nil { - return nil, nil, nil, nil, err - } - if !inp.Links.Validate(dss.Map(), ds.Map()) { + // validate + if _, f, err := ds.GraphLoader().ByGraphPointer(ctx, inp.Links); f == nil || err != nil { return nil, nil, nil, nil, interfaces.ErrInvalidPropertyLinks } } diff --git a/internal/usecase/interfaces/property.go b/internal/usecase/interfaces/property.go index 1f295fff..a9989f89 100644 --- a/internal/usecase/interfaces/property.go +++ b/internal/usecase/interfaces/property.go @@ -5,6 +5,7 @@ import ( "errors" "github.com/reearth/reearth-backend/internal/usecase" + "github.com/reearth/reearth-backend/pkg/dataset" "github.com/reearth/reearth-backend/pkg/file" "github.com/reearth/reearth-backend/pkg/id" "github.com/reearth/reearth-backend/pkg/property" @@ -30,7 +31,7 @@ type UploadFileParam struct { type LinkPropertyValueParam struct { PropertyID id.PropertyID Pointer *property.Pointer - Links *property.Links + Links *dataset.GraphPointer } type UnlinkPropertyValueParam struct { diff --git a/pkg/layer/merged_test.go b/pkg/layer/merged_test.go index d98b9c3a..b41ffe65 100644 --- a/pkg/layer/merged_test.go +++ b/pkg/layer/merged_test.go @@ -81,239 +81,275 @@ func TestMerge(t *testing.T) { Infobox(NewInfobox([]*InfoboxField{f2, f3}, ib2pr)). MustBuild() - expected1 := &Merged{ - Original: itemLayer1.ID(), - Parent: nil, - Scene: scene, - PluginID: &p, - ExtensionID: &e, - Property: &property.MergedMetadata{ - Original: &itemProperty, - Parent: nil, - LinkedDataset: nil, + tests := []struct { + name string + o Layer + p *Group + want *Merged + }{ + { + name: "nil", + o: nil, + p: nil, + want: nil, }, - } - - expected2 := &Merged{ - Original: itemLayer3.ID(), - Parent: nil, - Scene: scene, - PluginID: &p, - ExtensionID: &e, - Property: &property.MergedMetadata{ - Original: &itemProperty, - Parent: nil, - LinkedDataset: &dataset1, + { + name: "parent only", + o: nil, + p: groupLayer1, + want: nil, }, - Infobox: &MergedInfobox{ - Property: &property.MergedMetadata{ - Original: &ib1pr, - Parent: nil, - LinkedDataset: &dataset1, + { + name: "only original without infobox and link", + o: itemLayer1, + p: nil, + want: &Merged{ + Original: itemLayer1.ID(), + Parent: nil, + Scene: scene, + PluginID: &p, + ExtensionID: &e, + Property: &property.MergedMetadata{ + Original: &itemProperty, + Parent: nil, + LinkedDataset: nil, + }, }, - Fields: []*MergedInfoboxField{ - { - ID: f1.ID(), - Plugin: p, - Extension: e, - Property: &property.MergedMetadata{ - Original: &f1pr, - Parent: nil, - LinkedDataset: &dataset1, - }, + }, + { + name: "only original with infobox", + o: itemLayer3, + p: nil, + want: &Merged{ + Original: itemLayer3.ID(), + Parent: nil, + Scene: scene, + PluginID: &p, + ExtensionID: &e, + Property: &property.MergedMetadata{ + Original: &itemProperty, + Parent: nil, + LinkedDataset: &dataset1, }, - { - ID: f3.ID(), - Plugin: p, - Extension: e, + Infobox: &MergedInfobox{ Property: &property.MergedMetadata{ - Original: &f3pr, + Original: &ib1pr, Parent: nil, LinkedDataset: &dataset1, }, + Fields: []*MergedInfoboxField{ + { + ID: f1.ID(), + Plugin: p, + Extension: e, + Property: &property.MergedMetadata{ + Original: &f1pr, + Parent: nil, + LinkedDataset: &dataset1, + }, + }, + { + ID: f3.ID(), + Plugin: p, + Extension: e, + Property: &property.MergedMetadata{ + Original: &f3pr, + Parent: nil, + LinkedDataset: &dataset1, + }, + }, + }, }, }, }, - } - - expected3 := &Merged{ - Original: itemLayer2.ID(), - Parent: groupLayer1.IDRef(), - Scene: scene, - PluginID: &p, - ExtensionID: &e, - Property: &property.MergedMetadata{ - Original: &itemProperty, - Parent: &groupProperty, - LinkedDataset: &dataset1, - }, - } - - expected4 := &Merged{ - Original: itemLayer3.ID(), - Parent: groupLayer1.IDRef(), - Scene: scene, - PluginID: &p, - ExtensionID: &e, - Property: &property.MergedMetadata{ - Original: &itemProperty, - Parent: &groupProperty, - LinkedDataset: &dataset1, - }, - Infobox: &MergedInfobox{ - Property: &property.MergedMetadata{ - Original: &ib1pr, - Parent: nil, - LinkedDataset: &dataset1, + { + name: "original without infobox, parent without infobox", + o: itemLayer2, + p: groupLayer1, + want: &Merged{ + Original: itemLayer2.ID(), + Parent: groupLayer1.IDRef(), + Scene: scene, + PluginID: &p, + ExtensionID: &e, + Property: &property.MergedMetadata{ + Original: &itemProperty, + Parent: &groupProperty, + LinkedDataset: &dataset1, + }, }, - Fields: []*MergedInfoboxField{ - { - ID: f1.ID(), - Plugin: p, - Extension: e, - Property: &property.MergedMetadata{ - Original: &f1pr, - Parent: nil, - LinkedDataset: &dataset1, - }, + }, + { + name: "original with infobox, parent without infobox", + o: itemLayer3, + p: groupLayer1, + want: &Merged{ + Original: itemLayer3.ID(), + Parent: groupLayer1.IDRef(), + Scene: scene, + PluginID: &p, + ExtensionID: &e, + Property: &property.MergedMetadata{ + Original: &itemProperty, + Parent: &groupProperty, + LinkedDataset: &dataset1, }, - { - ID: f3.ID(), - Plugin: p, - Extension: e, + Infobox: &MergedInfobox{ Property: &property.MergedMetadata{ - Original: &f3pr, + Original: &ib1pr, Parent: nil, LinkedDataset: &dataset1, }, + Fields: []*MergedInfoboxField{ + { + ID: f1.ID(), + Plugin: p, + Extension: e, + Property: &property.MergedMetadata{ + Original: &f1pr, + Parent: nil, + LinkedDataset: &dataset1, + }, + }, + { + ID: f3.ID(), + Plugin: p, + Extension: e, + Property: &property.MergedMetadata{ + Original: &f3pr, + Parent: nil, + LinkedDataset: &dataset1, + }, + }, + }, }, }, }, - } - - expected5 := &Merged{ - Original: itemLayer2.ID(), - Parent: groupLayer2.IDRef(), - Scene: scene, - PluginID: &p, - ExtensionID: &e, - Property: &property.MergedMetadata{ - Original: &itemProperty, - Parent: &groupProperty, - LinkedDataset: &dataset1, - }, - Infobox: &MergedInfobox{ - Property: &property.MergedMetadata{ - Original: nil, - Parent: &ib2pr, - LinkedDataset: &dataset1, - }, - Fields: []*MergedInfoboxField{ - { - ID: f2.ID(), - Plugin: p, - Extension: e, - Property: &property.MergedMetadata{ - Original: &f2pr, - Parent: nil, - LinkedDataset: &dataset1, - }, + { + name: "original without infobox, parent with infobox", + o: itemLayer2, + p: groupLayer2, + want: &Merged{ + Original: itemLayer2.ID(), + Parent: groupLayer2.IDRef(), + Scene: scene, + PluginID: &p, + ExtensionID: &e, + Property: &property.MergedMetadata{ + Original: &itemProperty, + Parent: &groupProperty, + LinkedDataset: &dataset1, }, - { - ID: f3.ID(), - Plugin: p, - Extension: e, + Infobox: &MergedInfobox{ Property: &property.MergedMetadata{ - Original: &f3pr, - Parent: nil, + Original: nil, + Parent: &ib2pr, LinkedDataset: &dataset1, }, + Fields: []*MergedInfoboxField{ + { + ID: f2.ID(), + Plugin: p, + Extension: e, + Property: &property.MergedMetadata{ + Original: &f2pr, + Parent: nil, + LinkedDataset: &dataset1, + }, + }, + { + ID: f3.ID(), + Plugin: p, + Extension: e, + Property: &property.MergedMetadata{ + Original: &f3pr, + Parent: nil, + LinkedDataset: &dataset1, + }, + }, + }, }, }, }, - } - - expected6 := &Merged{ - Original: itemLayer3.ID(), - Parent: groupLayer2.IDRef(), - Scene: scene, - PluginID: &p, - ExtensionID: &e, - Property: &property.MergedMetadata{ - Original: &itemProperty, - Parent: &groupProperty, - LinkedDataset: &dataset1, - }, - Infobox: &MergedInfobox{ - Property: &property.MergedMetadata{ - Original: &ib1pr, - Parent: &ib2pr, - LinkedDataset: &dataset1, - }, - Fields: []*MergedInfoboxField{ - { - ID: f1.ID(), - Plugin: p, - Extension: e, + { + name: "original with infobox, parent with infobox", + o: itemLayer3, + p: groupLayer2, + want: &Merged{ + Original: itemLayer3.ID(), + Parent: groupLayer2.IDRef(), + Scene: scene, + PluginID: &p, + ExtensionID: &e, + Property: &property.MergedMetadata{ + Original: &itemProperty, + Parent: &groupProperty, + LinkedDataset: &dataset1, + }, + Infobox: &MergedInfobox{ Property: &property.MergedMetadata{ - Original: &f1pr, - Parent: nil, + Original: &ib1pr, + Parent: &ib2pr, LinkedDataset: &dataset1, }, + Fields: []*MergedInfoboxField{ + { + ID: f1.ID(), + Plugin: p, + Extension: e, + Property: &property.MergedMetadata{ + Original: &f1pr, + Parent: nil, + LinkedDataset: &dataset1, + }, + }, + { + ID: f3.ID(), + Plugin: p, + Extension: e, + Property: &property.MergedMetadata{ + Original: &f3pr, + Parent: nil, + LinkedDataset: &dataset1, + }, + }, + }, }, - { - ID: f3.ID(), - Plugin: p, - Extension: e, + }, + }, + { + name: "original with infobox but field is empty, parent with infobox", + o: itemLayer4, + p: groupLayer2, + want: &Merged{ + Original: itemLayer4.ID(), + Parent: groupLayer2.IDRef(), + Scene: scene, + PluginID: &p, + ExtensionID: &e, + Property: &property.MergedMetadata{ + Original: &itemProperty, + Parent: &groupProperty, + LinkedDataset: &dataset1, + }, + Infobox: &MergedInfobox{ Property: &property.MergedMetadata{ - Original: &f3pr, - Parent: nil, + Original: &ib1pr, + Parent: &ib2pr, LinkedDataset: &dataset1, }, + Fields: []*MergedInfoboxField{}, }, }, }, } - expected7 := &Merged{ - Original: itemLayer4.ID(), - Parent: groupLayer2.IDRef(), - Scene: scene, - PluginID: &p, - ExtensionID: &e, - Property: &property.MergedMetadata{ - Original: &itemProperty, - Parent: &groupProperty, - LinkedDataset: &dataset1, - }, - Infobox: &MergedInfobox{ - Property: &property.MergedMetadata{ - Original: &ib1pr, - Parent: &ib2pr, - LinkedDataset: &dataset1, - }, - Fields: []*MergedInfoboxField{}, - }, + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := Merge(tt.o, tt.p) + assert.Equal(t, tt.want, actual) + }) } - - actual := Merge(nil, nil) - assert.Nil(t, actual) - actual = Merge(nil, groupLayer1) - assert.Nil(t, actual) - actual = Merge(itemLayer1, nil) - assert.Equal(t, expected1, actual) - actual = Merge(itemLayer3, nil) - assert.Equal(t, expected2, actual) - actual = Merge(itemLayer2, groupLayer1) - assert.Equal(t, expected3, actual) - actual = Merge(itemLayer3, groupLayer1) - assert.Equal(t, expected4, actual) - actual = Merge(itemLayer2, groupLayer2) - assert.Equal(t, expected5, actual) - actual = Merge(itemLayer3, groupLayer2) - assert.Equal(t, expected6, actual) - actual = Merge(itemLayer4, groupLayer2) - assert.Equal(t, expected7, actual) } func TestMergedProperties(t *testing.T) { diff --git a/pkg/property/field.go b/pkg/property/field.go index d38ffa13..b8d836ab 100644 --- a/pkg/property/field.go +++ b/pkg/property/field.go @@ -17,7 +17,7 @@ var ( type Field struct { field id.PropertySchemaFieldID - links *Links + links *dataset.GraphPointer v *OptionalValue } @@ -33,7 +33,7 @@ func (p *Field) Field() id.PropertySchemaFieldID { return p.field } -func (p *Field) Links() *Links { +func (p *Field) Links() *dataset.GraphPointer { if p == nil { return nil } @@ -54,24 +54,21 @@ func (p *Field) Value() *Value { return p.v.Value() } -func (p *Field) ActualValue(ds *dataset.Dataset) *Value { +func (p *Field) ActualValue(ds *dataset.Dataset) *ValueAndDatasetValue { + var dv *dataset.Value if p.links != nil { - if l := p.links.Last(); l != nil { - ldid := l.Dataset() - ldsfid := l.DatasetSchemaField() - if ldid != nil || ldsfid != nil || ds.ID() == *ldid { - if f := ds.Field(*ldsfid); f != nil { - return valueFromDataset(f.Value()) - } + if l := p.links.Last(); !l.IsEmpty() { + d := l.Dataset() + if d != nil && ds.ID() == *d { + dv = ds.Field(l.Field()).Value() + } else { + return nil } + } else { + return nil } - return nil } - return p.Value() -} - -func (p *Field) HasLinkedField() bool { - return p.Links().IsLinked() + return NewValueAndDatasetValue(p.Type(), dv, p.Value()) } func (p *Field) CollectDatasets() []id.DatasetID { @@ -91,7 +88,7 @@ func (p *Field) CollectDatasets() []id.DatasetID { } func (p *Field) IsDatasetLinked(s id.DatasetSchemaID, i id.DatasetID) bool { - return p.Links().HasDatasetOrSchema(s, i) + return p.Links().HasSchemaAndDataset(s, i) } func (p *Field) Update(value *Value, field *SchemaField) error { @@ -112,7 +109,7 @@ func (p *Field) UpdateUnsafe(value *Value) { p.v.SetValue(value) } -func (p *Field) Link(links *Links) { +func (p *Field) Link(links *dataset.GraphPointer) { if p == nil { return } @@ -120,10 +117,7 @@ func (p *Field) Link(links *Links) { } func (p *Field) Unlink() { - if p == nil { - return - } - p.links = nil + p.Link(nil) } func (p *Field) UpdateField(field id.PropertySchemaFieldID) { @@ -156,9 +150,9 @@ func (p *Field) MigrateSchema(ctx context.Context, newSchema *Schema, dl dataset // If linked dataset is not compatible for type, it will be unlinked l := p.Links() if dl != nil && l.IsLinkedFully() { - if dsid, dsfid := l.Last().Dataset(), l.Last().DatasetSchemaField(); dsid != nil && dsfid != nil { + if dsid, dsfid := l.Last().Dataset(), l.Last().Field(); dsid != nil { dss, _ := dl(ctx, *dsid) - if dsf := dss[0].Field(*dsfid); dsf != nil { + if dsf := dss[0].Field(dsfid); dsf != nil { if schemaField.Type() != ValueType(dsf.Type()) { p.Unlink() } @@ -168,42 +162,3 @@ func (p *Field) MigrateSchema(ctx context.Context, newSchema *Schema, dl dataset return !invalid } - -func (p *Field) DatasetValue(ctx context.Context, d dataset.GraphLoader) (*dataset.Value, error) { - if p == nil { - return nil, nil - } - return p.links.DatasetValue(ctx, d) -} - -func (p *Field) MigrateDataset(q DatasetMigrationParam) { - if p == nil { - return - } - link := p.Links() - link.Replace(q.OldDatasetSchemaMap, q.OldDatasetMap, q.DatasetFieldIDMap) - if !link.Validate(q.NewDatasetSchemaMap, q.NewDatasetMap) { - p.Unlink() - } -} - -func (p *Field) ValidateSchema(ps *SchemaField) error { - if p == nil { - return nil - } - if ps == nil { - return errors.New("schema not found") - } - if p.v == nil { - return errors.New("invalid field value and type") - } - return nil -} - -type DatasetMigrationParam struct { - OldDatasetSchemaMap map[id.DatasetSchemaID]id.DatasetSchemaID - OldDatasetMap map[id.DatasetID]id.DatasetID - DatasetFieldIDMap map[id.DatasetSchemaFieldID]id.DatasetSchemaFieldID - NewDatasetSchemaMap map[id.DatasetSchemaID]*dataset.Schema - NewDatasetMap map[id.DatasetID]*dataset.Dataset -} diff --git a/pkg/property/field_builder.go b/pkg/property/field_builder.go index 00bbbae5..53de74e5 100644 --- a/pkg/property/field_builder.go +++ b/pkg/property/field_builder.go @@ -1,6 +1,9 @@ package property -import "github.com/reearth/reearth-backend/pkg/id" +import ( + "github.com/reearth/reearth-backend/pkg/dataset" + "github.com/reearth/reearth-backend/pkg/id" +) type FieldBuilder struct { p *Field @@ -50,7 +53,7 @@ func (b *FieldBuilder) Value(v *OptionalValue) *FieldBuilder { return b } -func (b *FieldBuilder) Link(l *Links) *FieldBuilder { +func (b *FieldBuilder) Link(l *dataset.GraphPointer) *FieldBuilder { b.p.links = l.Clone() return b } @@ -75,7 +78,7 @@ func (b *FieldUnsafeBuilder) ValueUnsafe(v *OptionalValue) *FieldUnsafeBuilder { return b } -func (b *FieldUnsafeBuilder) LinksUnsafe(l *Links) *FieldUnsafeBuilder { +func (b *FieldUnsafeBuilder) LinksUnsafe(l *dataset.GraphPointer) *FieldUnsafeBuilder { b.p.links = l.Clone() return b } diff --git a/pkg/property/field_builder_test.go b/pkg/property/field_builder_test.go index 0322ddef..d48c0ea6 100644 --- a/pkg/property/field_builder_test.go +++ b/pkg/property/field_builder_test.go @@ -4,6 +4,7 @@ import ( "errors" "testing" + "github.com/reearth/reearth-backend/pkg/dataset" "github.com/reearth/reearth-backend/pkg/id" "github.com/stretchr/testify/assert" ) @@ -17,22 +18,22 @@ func TestFieldBuilder_Value(t *testing.T) { func TestFieldBuilder_Link(t *testing.T) { p := NewSchemaField().ID("A").Type(ValueTypeString).MustBuild() - l := NewLink(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) - ls := NewLinks([]*Link{l}) + l := dataset.PointAt(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) + ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) b := NewField(p).Link(ls).MustBuild() assert.Equal(t, ls, b.Links()) } func TestFieldBuilder_Build(t *testing.T) { - l := NewLink(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) + l := dataset.PointAt(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) testCases := []struct { Name string - Links *Links + Links *dataset.GraphPointer Value *Value SF *SchemaField Expected struct { PType ValueType - Links *Links + Links *dataset.GraphPointer Value *Value } Err error @@ -41,7 +42,7 @@ func TestFieldBuilder_Build(t *testing.T) { Name: "fail invalid property id", Expected: struct { PType ValueType - Links *Links + Links *dataset.GraphPointer Value *Value }{}, Err: id.ErrInvalidID, @@ -52,7 +53,7 @@ func TestFieldBuilder_Build(t *testing.T) { Value: ValueTypeString.ValueFrom("vvv"), Expected: struct { PType ValueType - Links *Links + Links *dataset.GraphPointer Value *Value }{}, Err: ErrInvalidPropertyType, @@ -60,15 +61,15 @@ func TestFieldBuilder_Build(t *testing.T) { { Name: "success", SF: NewSchemaField().ID("A").Type(ValueTypeString).MustBuild(), - Links: NewLinks([]*Link{l}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), Value: ValueTypeString.ValueFrom("vvv"), Expected: struct { PType ValueType - Links *Links + Links *dataset.GraphPointer Value *Value }{ PType: ValueTypeString, - Links: NewLinks([]*Link{l}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), Value: ValueTypeString.ValueFrom("vvv"), }, Err: nil, @@ -91,16 +92,16 @@ func TestFieldBuilder_Build(t *testing.T) { } func TestFieldBuilder_MustBuild(t *testing.T) { - l := NewLink(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) + l := dataset.PointAt(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) testCases := []struct { Name string Fails bool - Links *Links + Links *dataset.GraphPointer Value *Value SF *SchemaField Expected struct { PType ValueType - Links *Links + Links *dataset.GraphPointer Value *Value } }{ @@ -109,7 +110,7 @@ func TestFieldBuilder_MustBuild(t *testing.T) { Fails: true, Expected: struct { PType ValueType - Links *Links + Links *dataset.GraphPointer Value *Value }{}, }, @@ -120,22 +121,22 @@ func TestFieldBuilder_MustBuild(t *testing.T) { Fails: true, Expected: struct { PType ValueType - Links *Links + Links *dataset.GraphPointer Value *Value }{}, }, { Name: "success", SF: NewSchemaField().ID("A").Type(ValueTypeString).MustBuild(), - Links: NewLinks([]*Link{l}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), Value: ValueTypeString.ValueFrom("vvv"), Expected: struct { PType ValueType - Links *Links + Links *dataset.GraphPointer Value *Value }{ PType: ValueTypeString, - Links: NewLinks([]*Link{l}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), Value: ValueTypeString.ValueFrom("vvv"), }, }, @@ -168,53 +169,53 @@ func TestNewFieldUnsafe(t *testing.T) { } func TestFieldUnsafeBuilder_Build(t *testing.T) { - l := NewLink(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) + l := dataset.PointAt(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) testCases := []struct { Name string - Links *Links + Links *dataset.GraphPointer Value *Value Type ValueType Field id.PropertySchemaFieldID Expected struct { PType ValueType Field id.PropertySchemaFieldID - Links *Links + Links *dataset.GraphPointer Value *Value } }{ { Name: "success", - Links: NewLinks([]*Link{l}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), Value: ValueTypeString.ValueFrom("vvv"), Type: ValueTypeString, Field: "a", Expected: struct { PType ValueType Field id.PropertySchemaFieldID - Links *Links + Links *dataset.GraphPointer Value *Value }{ PType: ValueTypeString, Field: "a", - Links: NewLinks([]*Link{l}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), Value: ValueTypeString.ValueFrom("vvv"), }, }, { Name: "nil value", - Links: NewLinks([]*Link{l}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), Value: nil, Type: ValueTypeString, Field: "a", Expected: struct { PType ValueType Field id.PropertySchemaFieldID - Links *Links + Links *dataset.GraphPointer Value *Value }{ PType: ValueTypeString, Field: "a", - Links: NewLinks([]*Link{l}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), Value: nil, }, }, diff --git a/pkg/property/field_test.go b/pkg/property/field_test.go index aade07fb..225b1fee 100644 --- a/pkg/property/field_test.go +++ b/pkg/property/field_test.go @@ -13,24 +13,24 @@ func TestField_ActualValue(t *testing.T) { dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() dssfid := id.NewDatasetSchemaFieldID() - l := NewLink(dsid, dssid, dssfid) - ls := NewLinks([]*Link{l}) + l := dataset.PointAt(dsid, dssid, dssfid) + ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) testCases := []struct { Name string Field *Field DS *dataset.Dataset - Expected *Value + Expected *ValueAndDatasetValue }{ { Name: "nil links", Field: NewField(p).Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).MustBuild(), - Expected: ValueTypeString.ValueFrom("vvv"), + Expected: NewValueAndDatasetValue(ValueTypeString, nil, ValueTypeString.ValueFrom("vvv")), }, { - Name: "nil last link", - Field: NewField(p).Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Link(&Links{}).MustBuild(), - Expected: nil, + Name: "empty links", + Field: NewField(p).Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Link(&dataset.GraphPointer{}).MustBuild(), + Expected: NewValueAndDatasetValue(ValueTypeString, nil, ValueTypeString.ValueFrom("vvv")), }, { Name: "dataset value", @@ -41,7 +41,13 @@ func TestField_ActualValue(t *testing.T) { dataset.NewField(dssfid, dataset.ValueTypeString.ValueFrom("xxx"), "")}, ). MustBuild(), - Expected: ValueTypeString.ValueFrom("xxx"), + Expected: NewValueAndDatasetValue(ValueTypeString, dataset.ValueTypeString.ValueFrom("xxx"), ValueTypeString.ValueFrom("vvv")), + }, + { + Name: "dataset value missing", + Field: NewField(p).Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Link(ls).MustBuild(), + DS: dataset.New().ID(dsid).Schema(dssid).MustBuild(), + Expected: NewValueAndDatasetValue(ValueTypeString, nil, ValueTypeString.ValueFrom("vvv")), }, } @@ -60,8 +66,8 @@ func TestField_CollectDatasets(t *testing.T) { dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() dssfid := id.NewDatasetSchemaFieldID() - l := NewLink(dsid, dssid, dssfid) - ls := NewLinks([]*Link{l}) + l := dataset.PointAt(dsid, dssid, dssfid) + ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) testCases := []struct { Name string @@ -91,8 +97,8 @@ func TestField_CollectDatasets(t *testing.T) { func TestField_Clone(t *testing.T) { p := NewSchemaField().ID("A").Type(ValueTypeString).MustBuild() - l := NewLink(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) - ls := NewLinks([]*Link{l}) + l := dataset.PointAt(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) + ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) b := NewField(p).Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Link(ls).MustBuild() r := b.Clone() assert.Equal(t, b, r) @@ -104,12 +110,12 @@ func TestField(t *testing.T) { p := NewSchemaField().ID("A").Type(ValueTypeString).MustBuild() b := NewField(p).MustBuild() assert.True(t, b.IsEmpty()) - l := NewLink(did, dsid, id.NewDatasetSchemaFieldID()) - ls := NewLinks([]*Link{l}) + l := dataset.PointAt(did, dsid, id.NewDatasetSchemaFieldID()) + ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) b.Link(ls) assert.True(t, b.IsDatasetLinked(dsid, did)) b.Unlink() - assert.False(t, b.HasLinkedField()) + assert.Nil(t, b.Links()) } func TestField_Update(t *testing.T) { diff --git a/pkg/property/group.go b/pkg/property/group.go index bbacd6ce..727138ef 100644 --- a/pkg/property/group.go +++ b/pkg/property/group.go @@ -3,7 +3,6 @@ package property import ( "context" "errors" - "fmt" "github.com/reearth/reearth-backend/pkg/dataset" "github.com/reearth/reearth-backend/pkg/id" @@ -53,7 +52,6 @@ func (g *Group) Schema() id.PropertySchemaID { return g.itemBase.Schema } -// SchemaRef _ func (g *Group) SchemaRef() *id.PropertySchemaID { if g == nil { return nil @@ -66,7 +64,7 @@ func (g *Group) HasLinkedField() bool { return false } for _, f := range g.fields { - if f.HasLinkedField() { + if f.Links() != nil { return true } } @@ -92,7 +90,7 @@ func (g *Group) FieldsByLinkedDataset(s id.DatasetSchemaID, i id.DatasetID) []*F } res := []*Field{} for _, f := range g.fields { - if f.Links().IsDatasetLinked(s, i) { + if f.Links().HasSchemaAndDataset(s, i) { res = append(res, f) } } @@ -224,15 +222,6 @@ func (g *Group) Field(fid id.PropertySchemaFieldID) *Field { return nil } -func (g *Group) MigrateDataset(q DatasetMigrationParam) { - if g == nil { - return - } - for _, f := range g.fields { - f.MigrateDataset(q) - } -} - func (g *Group) UpdateNameFieldValue(ps *Schema, value *Value) error { if g == nil || ps == nil || !g.Schema().Equal(ps.ID()) { return nil @@ -262,8 +251,9 @@ func (p *Group) ValidateSchema(ps *SchemaGroup) error { } for _, i := range p.fields { - if err := i.ValidateSchema(ps.Field(i.Field())); err != nil { - return fmt.Errorf("%s: %w", i.Field(), err) + f := ps.Field(i.Field()) + if f.Type() != i.Type() { + return errors.New("invalid field type") } } diff --git a/pkg/property/group_list.go b/pkg/property/group_list.go index e6ddb1cf..22f06c76 100644 --- a/pkg/property/group_list.go +++ b/pkg/property/group_list.go @@ -9,16 +9,13 @@ import ( "github.com/reearth/reearth-backend/pkg/id" ) -// GroupList _ type GroupList struct { itemBase groups []*Group } -// List implements Item interface var _ Item = &GroupList{} -// ID returns id func (g *GroupList) ID() id.PropertyItemID { if g == nil { return id.PropertyItemID{} @@ -26,7 +23,6 @@ func (g *GroupList) ID() id.PropertyItemID { return g.itemBase.ID } -// IDRef returns a reference of id func (g *GroupList) IDRef() *id.PropertyItemID { if g == nil { return nil @@ -34,7 +30,6 @@ func (g *GroupList) IDRef() *id.PropertyItemID { return g.itemBase.ID.Ref() } -// SchemaGroup returns id of schema group func (g *GroupList) SchemaGroup() id.PropertySchemaGroupID { if g == nil { return id.PropertySchemaGroupID("") @@ -42,7 +37,6 @@ func (g *GroupList) SchemaGroup() id.PropertySchemaGroupID { return g.itemBase.SchemaGroup } -// SchemaGroupRef _ func (g *GroupList) SchemaGroupRef() *id.PropertySchemaGroupID { if g == nil { return nil @@ -50,7 +44,6 @@ func (g *GroupList) SchemaGroupRef() *id.PropertySchemaGroupID { return g.itemBase.SchemaGroup.Ref() } -// Schema _ func (g *GroupList) Schema() id.PropertySchemaID { if g == nil { return id.PropertySchemaID{} @@ -58,7 +51,6 @@ func (g *GroupList) Schema() id.PropertySchemaID { return g.itemBase.Schema } -// SchemaRef _ func (g *GroupList) SchemaRef() *id.PropertySchemaID { if g == nil { return nil @@ -66,7 +58,6 @@ func (g *GroupList) SchemaRef() *id.PropertySchemaID { return g.itemBase.Schema.Ref() } -// HasLinkedField _ func (g *GroupList) HasLinkedField() bool { if g == nil { return false @@ -79,7 +70,6 @@ func (g *GroupList) HasLinkedField() bool { return false } -// CollectDatasets _ func (g *GroupList) CollectDatasets() []id.DatasetID { if g == nil { return nil @@ -93,7 +83,6 @@ func (g *GroupList) CollectDatasets() []id.DatasetID { return res } -// FieldsByLinkedDataset _ func (g *GroupList) FieldsByLinkedDataset(s id.DatasetSchemaID, i id.DatasetID) []*Field { if g == nil { return nil @@ -105,7 +94,6 @@ func (g *GroupList) FieldsByLinkedDataset(s id.DatasetSchemaID, i id.DatasetID) return res } -// IsDatasetLinked _ func (g *GroupList) IsDatasetLinked(s id.DatasetSchemaID, i id.DatasetID) bool { if g == nil { return false @@ -118,12 +106,10 @@ func (g *GroupList) IsDatasetLinked(s id.DatasetSchemaID, i id.DatasetID) bool { return false } -// IsEmpty _ func (g *GroupList) IsEmpty() bool { return g != nil && (g.groups == nil || len(g.groups) == 0) } -// Prune _ func (g *GroupList) Prune() { if g == nil { return @@ -133,7 +119,6 @@ func (g *GroupList) Prune() { } } -// MigrateSchema _ func (g *GroupList) MigrateSchema(ctx context.Context, newSchema *Schema, dl dataset.Loader) { if g == nil || dl == nil { return @@ -148,7 +133,6 @@ func (g *GroupList) MigrateSchema(ctx context.Context, newSchema *Schema, dl dat g.Prune() } -// Groups returns a slice of groups func (g *GroupList) Groups() []*Group { if g == nil { return nil @@ -156,7 +140,6 @@ func (g *GroupList) Groups() []*Group { return append([]*Group{}, g.groups...) } -// GetGroup returns a group whose id is specified func (g *GroupList) GetGroup(gid id.PropertyItemID) *Group { if g == nil { return nil @@ -169,7 +152,6 @@ func (g *GroupList) GetGroup(gid id.PropertyItemID) *Group { return nil } -// GroupAt returns a group whose index is specified func (g *GroupList) GroupAt(i int) *Group { if g == nil || i < 0 || i > len(g.groups)-1 { return nil @@ -177,7 +159,6 @@ func (g *GroupList) GroupAt(i int) *Group { return g.groups[i] } -// Has _ func (g *GroupList) Has(i id.PropertyItemID) bool { if g == nil { return false @@ -190,7 +171,6 @@ func (g *GroupList) Has(i id.PropertyItemID) bool { return false } -// Count _ func (g *GroupList) Count() int { if g == nil { return 0 @@ -198,7 +178,6 @@ func (g *GroupList) Count() int { return len(g.groups) } -// Add _ func (g *GroupList) Add(gg *Group, index int) { if g == nil || g.Has(gg.ID()) { return @@ -212,7 +191,6 @@ func (g *GroupList) Add(gg *Group, index int) { } } -// AddOrMove _ func (g *GroupList) AddOrMove(gg *Group, index int) { if g == nil { return @@ -231,7 +209,6 @@ func (g *GroupList) AddOrMove(gg *Group, index int) { g.groups = append(g.groups[:index], append([]*Group{gg}, g.groups[index:]...)...) } -// Move _ func (g *GroupList) Move(id id.PropertyItemID, toIndex int) { if g == nil { return @@ -245,7 +222,6 @@ func (g *GroupList) Move(id id.PropertyItemID, toIndex int) { } } -// MoveAt _ func (g *GroupList) MoveAt(fromIndex int, toIndex int) { if g == nil { return @@ -270,7 +246,6 @@ func (g *GroupList) MoveAt(fromIndex int, toIndex int) { g.groups = append(newSlice, g.groups[toIndex:]...) } -// Remove _ func (g *GroupList) Remove(id id.PropertyItemID) bool { if g == nil { return false @@ -286,7 +261,6 @@ func (g *GroupList) Remove(id id.PropertyItemID) bool { return false } -// RemoveAt _ func (g *GroupList) RemoveAt(index int) { if g == nil { return @@ -305,7 +279,6 @@ func (g *GroupList) RemoveAt(index int) { g.groups = append(g.groups[:index], groups...) } -// Empty _ func (g *GroupList) Empty() { if g == nil { return @@ -314,7 +287,6 @@ func (g *GroupList) Empty() { g.groups = []*Group{} } -// GetOrCreateField _ func (g *GroupList) GetOrCreateField(ps *Schema, ptr *Pointer) (*Field, bool) { if g == nil || ptr == nil || ps == nil || ps.ID() != g.Schema() { return nil, false @@ -337,7 +309,6 @@ func (g *GroupList) GetOrCreateField(ps *Schema, ptr *Pointer) (*Field, bool) { return i.GetOrCreateField(ps, fid) } -// CreateAndAddListItem _ func (g *GroupList) CreateAndAddListItem(ps *Schema, index *int) *Group { if g == nil || ps == nil || !g.Schema().Equal(ps.ID()) { return nil @@ -360,16 +331,6 @@ func (g *GroupList) CreateAndAddListItem(ps *Schema, index *int) *Group { return nil } -// MigrateDataset _ -func (g *GroupList) MigrateDataset(q DatasetMigrationParam) { - if g == nil { - return - } - for _, f := range g.groups { - f.MigrateDataset(q) - } -} - func (p *GroupList) ValidateSchema(ps *SchemaGroup) error { if p == nil { return nil diff --git a/pkg/property/group_list_test.go b/pkg/property/group_list_test.go index 39329d43..dd120340 100644 --- a/pkg/property/group_list_test.go +++ b/pkg/property/group_list_test.go @@ -3,6 +3,7 @@ package property import ( "testing" + "github.com/reearth/reearth-backend/pkg/dataset" "github.com/reearth/reearth-backend/pkg/id" "github.com/stretchr/testify/assert" ) @@ -47,7 +48,7 @@ func TestGroupList_HasLinkedField(t *testing.T) { v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() - f := NewField(sf).Value(OptionalValueFrom(v)).Link(&Links{links: []*Link{NewLink(dsid, dssid, id.NewDatasetSchemaFieldID())}}).MustBuild() + f := NewField(sf).Value(OptionalValueFrom(v)).Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID())})).MustBuild() groups := []*Group{NewGroup().ID(pid).Fields([]*Field{f}).MustBuild()} groups2 := []*Group{NewGroup().ID(pid).MustBuild()} testCases := []struct { @@ -85,7 +86,7 @@ func TestGroupList_CollectDatasets(t *testing.T) { v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() - f := NewField(sf).Value(OptionalValueFrom(v)).Link(&Links{links: []*Link{NewLink(dsid, dssid, id.NewDatasetSchemaFieldID())}}).MustBuild() + f := NewField(sf).Value(OptionalValueFrom(v)).Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID())})).MustBuild() groups := []*Group{NewGroup().ID(pid).Fields([]*Field{f}).MustBuild()} groups2 := []*Group{NewGroup().ID(pid).MustBuild()} testCases := []struct { @@ -122,7 +123,7 @@ func TestGroupList_FieldsByLinkedDataset(t *testing.T) { v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() - f := NewField(sf).Value(OptionalValueFrom(v)).Link(&Links{links: []*Link{NewLink(dsid, dssid, id.NewDatasetSchemaFieldID())}}).MustBuild() + f := NewField(sf).Value(OptionalValueFrom(v)).Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID())})).MustBuild() groups := []*Group{NewGroup().ID(pid).Fields([]*Field{f}).MustBuild()} groups2 := []*Group{NewGroup().ID(pid).MustBuild()} testCases := []struct { @@ -159,7 +160,7 @@ func TestGroupList_IsEmpty(t *testing.T) { v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() - f := NewField(sf).Value(OptionalValueFrom(v)).Link(&Links{links: []*Link{NewLink(dsid, dssid, id.NewDatasetSchemaFieldID())}}).MustBuild() + f := NewField(sf).Value(OptionalValueFrom(v)).Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID())})).MustBuild() groups := []*Group{NewGroup().ID(pid).Fields([]*Field{f}).MustBuild()} testCases := []struct { Name string diff --git a/pkg/property/group_test.go b/pkg/property/group_test.go index 1321a14c..3b31b30b 100644 --- a/pkg/property/group_test.go +++ b/pkg/property/group_test.go @@ -4,6 +4,7 @@ import ( "errors" "testing" + "github.com/reearth/reearth-backend/pkg/dataset" "github.com/reearth/reearth-backend/pkg/id" "github.com/stretchr/testify/assert" ) @@ -29,8 +30,8 @@ func TestGroup_SchemaGroup(t *testing.T) { func TestGroup_HasLinkedField(t *testing.T) { sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") - l := NewLink(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) - ls := NewLinks([]*Link{l}) + l := dataset.PointAt(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) + ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) f := NewField(sf).Value(OptionalValueFrom(v)).Link(ls).MustBuild() f2 := NewField(sf).Value(OptionalValueFrom(v)).MustBuild() @@ -69,8 +70,8 @@ func TestGroup_IsDatasetLinked(t *testing.T) { v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() - l := NewLink(dsid, dssid, id.NewDatasetSchemaFieldID()) - ls := NewLinks([]*Link{l}) + l := dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID()) + ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) f := NewField(sf).Value(OptionalValueFrom(v)).Link(ls).MustBuild() f2 := NewField(sf).Value(OptionalValueFrom(v)).MustBuild() @@ -111,8 +112,8 @@ func TestGroup_CollectDatasets(t *testing.T) { sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() - l := NewLink(dsid, id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) - ls := NewLinks([]*Link{l}) + l := dataset.PointAt(dsid, id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) + ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) f := NewField(sf).Value(OptionalValueFrom(v)).Link(ls).MustBuild() testCases := []struct { @@ -146,8 +147,8 @@ func TestGroup_FieldsByLinkedDataset(t *testing.T) { v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() - l := NewLink(dsid, dssid, id.NewDatasetSchemaFieldID()) - ls := NewLinks([]*Link{l}) + l := dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID()) + ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) f := NewField(sf).Value(OptionalValueFrom(v)).Link(ls).MustBuild() testCases := []struct { diff --git a/pkg/property/initializer.go b/pkg/property/initializer.go index aff489fe..07c33245 100644 --- a/pkg/property/initializer.go +++ b/pkg/property/initializer.go @@ -5,6 +5,7 @@ package property import ( "errors" + "github.com/reearth/reearth-backend/pkg/dataset" "github.com/reearth/reearth-backend/pkg/id" ) @@ -264,16 +265,16 @@ func (p *InitializerField) PropertyField() *Field { return nil } - var plinks *Links + var plinks *dataset.GraphPointer if p.Links != nil { - links := make([]*Link, 0, len(p.Links)) + links := make([]*dataset.Pointer, 0, len(p.Links)) for _, l := range p.Links { link := l.PropertyLink() if link != nil { links = append(links, link) } } - plinks = NewLinks(links) + plinks = dataset.NewGraphPointer(links) } return NewFieldUnsafe().LinksUnsafe(plinks).FieldUnsafe(p.Field).ValueUnsafe(NewOptionalValue(p.Type, p.Value.Clone())).Build() @@ -297,14 +298,14 @@ func (p *InitializerLink) Clone() *InitializerLink { } } -func (p *InitializerLink) PropertyLink() *Link { +func (p *InitializerLink) PropertyLink() *dataset.Pointer { if p == nil { return nil } if p.Dataset == nil { - return NewLinkFieldOnly(p.Schema, p.Field) + return dataset.PointAtField(p.Schema, p.Field) } - return NewLink(*p.Dataset, p.Schema, p.Field) + return dataset.PointAt(*p.Dataset, p.Schema, p.Field) } diff --git a/pkg/property/initializer_test.go b/pkg/property/initializer_test.go index ebd6fe1e..67bdc1ac 100644 --- a/pkg/property/initializer_test.go +++ b/pkg/property/initializer_test.go @@ -3,6 +3,7 @@ package property import ( "testing" + "github.com/reearth/reearth-backend/pkg/dataset" "github.com/reearth/reearth-backend/pkg/id" "github.com/stretchr/testify/assert" ) @@ -260,7 +261,7 @@ func TestInitializerField_PropertyField(t *testing.T) { expected := NewFieldUnsafe(). FieldUnsafe(field.Field). ValueUnsafe(NewOptionalValue(field.Type, field.Value)). - LinksUnsafe(NewLinks([]*Link{NewLink(*field.Links[0].Dataset.CopyRef(), field.Links[0].Schema, field.Links[0].Field)})). + LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(*field.Links[0].Dataset.CopyRef(), field.Links[0].Schema, field.Links[0].Field)})). Build() assert.Equal(t, expected, field.PropertyField()) @@ -285,7 +286,7 @@ func TestInitializerLink_PropertyLink(t *testing.T) { Field: id.NewDatasetSchemaFieldID(), } - expected := NewLink(*link.Dataset.CopyRef(), link.Schema, link.Field) + expected := dataset.PointAt(*link.Dataset.CopyRef(), link.Schema, link.Field) assert.Equal(t, expected, link.PropertyLink()) } diff --git a/pkg/property/item.go b/pkg/property/item.go index 65807e0b..b26055e1 100644 --- a/pkg/property/item.go +++ b/pkg/property/item.go @@ -21,7 +21,6 @@ type Item interface { IsEmpty() bool Prune() MigrateSchema(context.Context, *Schema, dataset.Loader) - MigrateDataset(DatasetMigrationParam) ValidateSchema(*SchemaGroup) error } diff --git a/pkg/property/link.go b/pkg/property/link.go deleted file mode 100644 index e1f62a06..00000000 --- a/pkg/property/link.go +++ /dev/null @@ -1,443 +0,0 @@ -package property - -import ( - "context" - - "github.com/reearth/reearth-backend/pkg/dataset" - "github.com/reearth/reearth-backend/pkg/id" -) - -// Links _ -type Links struct { - links []*Link -} - -// Link _ -type Link struct { - dataset *id.DatasetID - schema *id.DatasetSchemaID - field *id.DatasetSchemaFieldID -} - -// NewLinks _ -func NewLinks(links []*Link) *Links { - if links == nil { - return nil - } - links2 := make([]*Link, 0, len(links)) - for _, l := range links { - l2 := *l - links2 = append(links2, &l2) - } - return &Links{ - links: links2, - } -} - -// Clone _ -func (l *Links) Clone() *Links { - if l == nil { - return nil - } - return &Links{ - links: append([]*Link{}, l.links...), - } -} - -// IsLinked _ -func (l *Links) IsLinked() bool { - return l != nil && l.links != nil && len(l.links) > 0 -} - -// IsLinkedFully _ -func (l *Links) IsLinkedFully() bool { - return l != nil && l.links != nil && len(l.links) > 0 && len(l.DatasetIDs()) == len(l.links) -} - -// Len _ -func (l *Links) Len() int { - if l == nil || l.links == nil { - return 0 - } - return len(l.links) -} - -// First _ -func (l *Links) First() *Link { - if l == nil || l.links == nil || len(l.links) == 0 { - return nil - } - return l.links[0] -} - -// Last _ -func (l *Links) Last() *Link { - if l == nil || l.links == nil || len(l.links) == 0 { - return nil - } - return l.links[len(l.links)-1] -} - -// LastValue _ -func (l *Links) LastValue(ds *dataset.Dataset) *dataset.Value { - return l.Last().Value(ds) -} - -// Validate _ -func (l *Links) Validate(dsm dataset.SchemaMap, dm dataset.Map) bool { - if l == nil || l.links == nil { - return false - } - firstDatasetSchema := l.First().DatasetSchema() - if firstDatasetSchema == nil { - return false - } - fields := l.DatasetSchemaFieldIDs() - if fields == nil || len(fields) != len(l.links) { - return false - } - firstDataset := l.First().Dataset() - - res, resf := dsm.GraphSearchByFields(*firstDatasetSchema, fields...) - if len(res) != len(l.links) || resf == nil { - return false - } - - if firstDataset != nil { - res2, resf2 := dm.GraphSearchByFields(*firstDataset, fields...) - return len(res2) == len(l.links) && resf2 != nil - } - - return true -} - -// Replace _ -func (l *Links) Replace( - dsm map[id.DatasetSchemaID]id.DatasetSchemaID, - dm map[id.DatasetID]id.DatasetID, - fm map[id.DatasetSchemaFieldID]id.DatasetSchemaFieldID, -) { - if l == nil || l.links == nil { - return - } - - links := make([]*Link, 0, len(l.links)) - - for _, link := range l.links { - nl := &Link{} - - if link.schema != nil { - if nds, ok := dsm[*link.schema]; ok { - nid := nds - nl.schema = &nid - } else { - // Datasetは全てIDが再割り当てされるため、リンクが途切れていることになる - // よってリンク自体が無効になる - l.links = nil - return - } - } - - if link.dataset != nil { - if nds, ok := dm[*link.dataset]; ok { - nid := nds - nl.dataset = &nid - } else { - // Datasetは全てIDが再割り当てされるため、リンクが途切れていることになる - // よってリンク自体が無効になる - l.links = nil - return - } - } - - if link.field != nil { - if nf, ok := fm[*link.field]; ok { - nid := nf - nl.field = &nid - } else { - // Datasetは全てIDが再割り当てされるため、リンクが途切れていることになる - // よってリンク自体が無効になる - l.links = nil - return - } - } - - links = append(links, nl) - } - - l.links = links -} - -// Links _ -func (l *Links) Links() []*Link { - if l == nil || l.links == nil || len(l.links) == 0 { - return nil - } - links2 := make([]*Link, 0, len(l.links)) - for _, l := range l.links { - l2 := *l - links2 = append(links2, &l2) - } - return links2 -} - -// DatasetIDs _ -func (l *Links) DatasetIDs() []id.DatasetID { - if l == nil { - return nil - } - datasets := make([]id.DatasetID, 0, len(l.links)) - for _, i := range l.links { - if i.dataset != nil { - datasets = append(datasets, *i.dataset) - } else { - return datasets - } - } - return datasets -} - -// DatasetSchemaIDs _ -func (l *Links) DatasetSchemaIDs() []id.DatasetSchemaID { - if l == nil { - return nil - } - schemas := make([]id.DatasetSchemaID, 0, len(l.links)) - for _, i := range l.links { - if i.schema != nil { - schemas = append(schemas, *i.schema) - } else { - return schemas - } - } - return schemas -} - -// IsDatasetLinked _ -func (l *Links) IsDatasetLinked(s id.DatasetSchemaID, dsid id.DatasetID) bool { - if l == nil { - return false - } - for _, id := range l.DatasetSchemaIDs() { - if id == s { - return true - } - } - for _, id := range l.DatasetIDs() { - if id == dsid { - return true - } - } - return false -} - -// DatasetSchemaFieldIDs _ -func (l *Links) DatasetSchemaFieldIDs() []id.DatasetSchemaFieldID { - if l == nil { - return nil - } - fields := make([]id.DatasetSchemaFieldID, 0, len(l.links)) - for _, i := range l.links { - if i.field != nil { - fields = append(fields, *i.field) - } else { - return fields - } - } - return fields -} - -// HasDataset _ -func (l *Links) HasDataset(did id.DatasetID) bool { - if l == nil { - return false - } - for _, l2 := range l.links { - if l2 != nil && l2.dataset != nil && *l2.dataset == did { - return true - } - } - return false -} - -// HasDatasetSchema _ -func (l *Links) HasDatasetSchema(dsid id.DatasetSchemaID) bool { - if l == nil { - return false - } - for _, l2 := range l.links { - if l2 != nil && l2.schema != nil && *l2.schema == dsid { - return true - } - } - return false -} - -func (l *Links) HasDatasetOrSchema(dsid id.DatasetSchemaID, did id.DatasetID) bool { - if l == nil { - return false - } - for _, l2 := range l.links { - if l2 != nil && (l2.schema != nil && *l2.schema == dsid || l2.dataset != nil && *l2.dataset == did) { - return true - } - } - return false -} - -// NewLink _ -func NewLink(d id.DatasetID, ds id.DatasetSchemaID, f id.DatasetSchemaFieldID) *Link { - dataset := d - schema := ds - field := f - return &Link{ - dataset: &dataset, - schema: &schema, - field: &field, - } -} - -// NewLinkFieldOnly _ -func NewLinkFieldOnly(ds id.DatasetSchemaID, f id.DatasetSchemaFieldID) *Link { - schema := ds - field := f - return &Link{ - schema: &schema, - field: &field, - } -} - -// Dataset _ -func (l *Link) Dataset() *id.DatasetID { - if l == nil || l.dataset == nil { - return nil - } - dataset := *l.dataset - return &dataset -} - -// DatasetSchema _ -func (l *Link) DatasetSchema() *id.DatasetSchemaID { - if l == nil || l.schema == nil { - return nil - } - datasetSchema := *l.schema - return &datasetSchema -} - -// DatasetSchemaField _ -func (l *Link) DatasetSchemaField() *id.DatasetSchemaFieldID { - if l == nil || l.field == nil { - return nil - } - field := *l.field - return &field -} - -// Value _ -func (l *Link) Value(ds *dataset.Dataset) *dataset.Value { - if l == nil || ds == nil || l.dataset == nil || l.field == nil || ds.ID() != *l.dataset { - return nil - } - f := ds.Field(*l.field) - if f == nil { - return nil - } - return f.Value() -} - -// Validate _ -func (l *Link) Validate(dss *dataset.Schema, ds *dataset.Dataset) bool { - if l == nil || l.field == nil || l.schema == nil || dss == nil { - return false - } - - // DS - if dss.ID() != *l.schema { - return false - } - if f := dss.Field(*l.field); f == nil { - return false - } - - // D - if l.dataset != nil { - if ds == nil || ds.ID() != *l.dataset || ds.Schema() != dss.ID() { - return false - } - if f := ds.Field(*l.field); f == nil { - return false - } - } - - return true -} - -// IsEmpty _ -func (l *Links) IsEmpty() bool { - return l == nil || l.links == nil || len(l.links) == 0 -} - -// Clone _ -func (l *Link) Clone() *Link { - if l == nil { - return nil - } - return &Link{ - dataset: l.Dataset(), - schema: l.DatasetSchema(), - field: l.DatasetSchemaField(), - } -} - -// ApplyDataset _ -func (l *Link) ApplyDataset(ds *id.DatasetID) *Link { - if l == nil { - return nil - } - // if dataset is already set, it will not be overriden - if ds == nil || l.Dataset() != nil { - return l.Clone() - } - ds2 := *ds - return &Link{ - dataset: &ds2, - schema: l.DatasetSchema(), - field: l.DatasetSchemaField(), - } -} - -// ApplyDataset _ -func (l *Links) ApplyDataset(ds *id.DatasetID) *Links { - if l == nil || l.links == nil || len(l.links) == 0 { - return nil - } - - links := l.Clone() - first := links.First() - // if dataset is already set, it will not be overriden - if ds == nil || first.Dataset() != nil { - return links - } - - links.links[0] = first.ApplyDataset(ds) - return links -} - -func (l *Links) DatasetValue(ctx context.Context, d dataset.GraphLoader) (*dataset.Value, error) { - if l == nil || d == nil { - return nil, nil - } - dsid := l.First().Dataset() - dsfid := l.DatasetSchemaFieldIDs() - if dsid != nil && dsfid != nil { - _, dsf, err := d(ctx, *dsid, dsfid...) - if err != nil { - return nil, err - } - if dsf != nil { - return dsf.Value(), nil - } - } - return nil, nil -} diff --git a/pkg/property/link_test.go b/pkg/property/link_test.go deleted file mode 100644 index 706b8565..00000000 --- a/pkg/property/link_test.go +++ /dev/null @@ -1,481 +0,0 @@ -package property - -import ( - "testing" - - "github.com/reearth/reearth-backend/pkg/dataset" - - "github.com/reearth/reearth-backend/pkg/id" - "github.com/stretchr/testify/assert" -) - -func TestNewLinks(t *testing.T) { - dsid1 := id.NewDatasetSchemaID() - dsid2 := id.NewDatasetSchemaID() - did1 := id.NewDatasetID() - did2 := id.NewDatasetID() - dfid1 := id.NewDatasetSchemaFieldID() - dfid2 := id.NewDatasetSchemaFieldID() - - var lin *Links - assert.Nil(t, lin) - assert.Nil(t, lin.Clone()) - assert.Nil(t, lin.Links()) - assert.Nil(t, lin.DatasetIDs()) - assert.Nil(t, lin.DatasetSchemaIDs()) - assert.False(t, lin.IsLinked()) - assert.Equal(t, 0, lin.Len()) - - lin = NewLinks([]*Link{}) - assert.Equal(t, []id.DatasetID{}, lin.DatasetIDs()) - assert.Equal(t, []id.DatasetSchemaID{}, lin.DatasetSchemaIDs()) - assert.Equal(t, []id.DatasetSchemaFieldID{}, lin.DatasetSchemaFieldIDs()) - - ll := []*Link{ - NewLink(did1, dsid1, dfid1), - NewLink(did2, dsid2, dfid2), - } - dl := []id.DatasetID{did1, did2} - dsl := []id.DatasetSchemaID{dsid1, dsid2} - dsfl := []id.DatasetSchemaFieldID{dfid1, dfid2} - lin = NewLinks(ll) - assert.NotNil(t, lin) - assert.Equal(t, ll, lin.Links()) - assert.Equal(t, ll, lin.Clone().Links()) - assert.Equal(t, dl, lin.DatasetIDs()) - assert.Equal(t, dsl, lin.DatasetSchemaIDs()) - assert.Equal(t, dsfl, lin.DatasetSchemaFieldIDs()) - assert.True(t, lin.IsLinked()) - assert.Equal(t, 2, lin.Len()) -} - -func TestLinks_IsDatasetLinked(t *testing.T) { - dsid1 := id.NewDatasetSchemaID() - dsid2 := id.NewDatasetSchemaID() - did1 := id.NewDatasetID() - did2 := id.NewDatasetID() - dfid1 := id.NewDatasetSchemaFieldID() - ll := []*Link{ - NewLink(did1, dsid1, dfid1), - } - - testCases := []struct { - Name string - DSS id.DatasetSchemaID - DS id.DatasetID - Links *Links - Expected bool - }{ - { - Name: "nil links", - Expected: false, - }, - { - Name: "true", - DSS: dsid1, - DS: did1, - Links: NewLinks(ll), - Expected: true, - }, - { - Name: "false", - DSS: dsid2, - DS: did2, - Links: NewLinks(ll), - Expected: false, - }, - } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - res := tc.Links.IsDatasetLinked(tc.DSS, tc.DS) - res2 := tc.Links.HasDataset(tc.DS) - res3 := tc.Links.HasDatasetSchema(tc.DSS) - assert.Equal(tt, tc.Expected, res) - assert.Equal(tt, tc.Expected, res2) - assert.Equal(tt, tc.Expected, res3) - }) - } -} - -func TestLinks_Validate(t *testing.T) { - dsid1 := id.NewDatasetSchemaID() - did1 := id.NewDatasetID() - dfid1 := id.NewDatasetSchemaFieldID() - - testCases := []struct { - Name string - DSM dataset.SchemaMap - DM dataset.Map - Links *Links - Expected bool - }{ - { - Name: "nil links", - Expected: false, - }, - { - Name: "nil dataset schema for first link", - Links: NewLinks([]*Link{}), - Expected: false, - }, - { - Name: "len(res) != len(l.links)", - Links: NewLinks([]*Link{NewLink(did1, dsid1, dfid1)}), - Expected: false, - }, - { - Name: "success", - DSM: dataset.SchemaMap{ - dsid1: dataset.NewSchema().ID(dsid1).Fields([]*dataset.SchemaField{ - dataset.NewSchemaField(). - ID(dfid1). - Ref(dsid1.Ref()).Type(dataset.ValueTypeString). - MustBuild(), - }).MustBuild(), - }, - DM: dataset.Map{ - did1: dataset.New().ID(did1).Schema(dsid1).Fields([]*dataset.Field{ - dataset.NewField(dfid1, dataset.ValueTypeString.ValueFrom("vvv"), ""), - }).MustBuild(), - }, - Links: NewLinks([]*Link{NewLink(did1, dsid1, dfid1)}), - Expected: true, - }, - } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - res := tc.Links.Validate(tc.DSM, tc.DM) - assert.Equal(tt, tc.Expected, res) - }) - } -} - -func TestLinks_Replace(t *testing.T) { - dsid1 := id.NewDatasetSchemaID() - dsid2 := id.NewDatasetSchemaID() - did1 := id.NewDatasetID() - did2 := id.NewDatasetID() - dfid1 := id.NewDatasetSchemaFieldID() - dfid2 := id.NewDatasetSchemaFieldID() - - testCases := []struct { - Name string - DSM map[id.DatasetSchemaID]id.DatasetSchemaID - DM map[id.DatasetID]id.DatasetID - FM map[id.DatasetSchemaFieldID]id.DatasetSchemaFieldID - Expected, Links *Links - }{ - { - Name: "nil links", - }, - { - Name: "success", - DSM: map[id.DatasetSchemaID]id.DatasetSchemaID{ - dsid1: dsid2, - }, - DM: map[id.DatasetID]id.DatasetID{ - did1: did2, - }, - FM: map[id.DatasetSchemaFieldID]id.DatasetSchemaFieldID{ - dfid1: dfid2, - }, - Links: NewLinks([]*Link{NewLink(did1, dsid1, dfid1)}), - Expected: NewLinks([]*Link{NewLink(did2, dsid2, dfid2)}), - }, - { - Name: "dataset = nil", - DSM: map[id.DatasetSchemaID]id.DatasetSchemaID{ - dsid1: dsid2, - }, - DM: map[id.DatasetID]id.DatasetID{}, - FM: map[id.DatasetSchemaFieldID]id.DatasetSchemaFieldID{ - dfid1: dfid2, - }, - Links: NewLinks([]*Link{NewLink(did1, dsid1, dfid1)}), - }, - { - Name: "datasetschema = nil", - DSM: map[id.DatasetSchemaID]id.DatasetSchemaID{}, - DM: map[id.DatasetID]id.DatasetID{ - did1: did2, - }, - FM: map[id.DatasetSchemaFieldID]id.DatasetSchemaFieldID{ - dfid1: dfid2, - }, - Links: NewLinks([]*Link{NewLink(did1, dsid1, dfid1)}), - }, - { - Name: "dataset schema field = nil", - DSM: map[id.DatasetSchemaID]id.DatasetSchemaID{ - dsid1: dsid2, - }, - DM: map[id.DatasetID]id.DatasetID{ - did1: did2, - }, - FM: map[id.DatasetSchemaFieldID]id.DatasetSchemaFieldID{}, - Links: NewLinks([]*Link{NewLink(did1, dsid1, dfid1)}), - }, - } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - tc.Links.Replace(tc.DSM, tc.DM, tc.FM) - assert.Equal(tt, tc.Expected.Links(), tc.Links.Links()) - }) - } -} - -func TestLinks_ApplyDataset(t *testing.T) { - dsid1 := id.NewDatasetSchemaID() - did1 := id.NewDatasetID() - dfid1 := id.NewDatasetSchemaFieldID() - - testCases := []struct { - Name string - Input *id.DatasetID - Expected, Links *Links - }{ - { - Name: "nil links", - }, - { - Name: "nil input dataset", - Links: NewLinks([]*Link{NewLinkFieldOnly(dsid1, dfid1)}), - Expected: NewLinks([]*Link{NewLinkFieldOnly(dsid1, dfid1)}), - }, - { - Name: "not nil dataset", - Links: NewLinks([]*Link{NewLink(did1, dsid1, dfid1)}), - Expected: NewLinks([]*Link{NewLink(did1, dsid1, dfid1)}), - }, - { - Name: "apply new dataset", - Input: did1.Ref(), - Links: NewLinks([]*Link{NewLinkFieldOnly(dsid1, dfid1)}), - Expected: NewLinks([]*Link{NewLink(did1, dsid1, dfid1)}), - }, - } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - res := tc.Links.ApplyDataset(tc.Input) - assert.Equal(tt, tc.Expected, res) - }) - } -} - -func TestLink_Dataset(t *testing.T) { - dsid1 := id.NewDatasetSchemaID() - did1 := id.NewDatasetID() - dfid1 := id.NewDatasetSchemaFieldID() - - testCases := []struct { - Name string - Link *Link - Expected *id.DatasetID - }{ - { - Name: "nil link", - }, - { - Name: "nil dataset", - Link: NewLinkFieldOnly(dsid1, dfid1), - }, - { - Name: "success", - Link: NewLink(did1, dsid1, dfid1), - Expected: did1.Ref(), - }, - } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - res := tc.Link.Dataset() - assert.Equal(tt, tc.Expected, res) - }) - } - -} - -func TestLink_DatasetSchema(t *testing.T) { - dsid1 := id.NewDatasetSchemaID() - did1 := id.NewDatasetID() - dfid1 := id.NewDatasetSchemaFieldID() - - testCases := []struct { - Name string - Link *Link - Expected *id.DatasetSchemaID - }{ - { - Name: "nil link", - }, - { - Name: "success", - Link: NewLink(did1, dsid1, dfid1), - Expected: dsid1.Ref(), - }, - } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - res := tc.Link.DatasetSchema() - assert.Equal(tt, tc.Expected, res) - }) - } - -} - -func TestLink_DatasetSchemaField(t *testing.T) { - dsid1 := id.NewDatasetSchemaID() - did1 := id.NewDatasetID() - dfid1 := id.NewDatasetSchemaFieldID() - - testCases := []struct { - Name string - Link *Link - Expected *id.DatasetSchemaFieldID - }{ - { - Name: "nil link", - }, - { - Name: "success", - Link: NewLink(did1, dsid1, dfid1), - Expected: dfid1.Ref(), - }, - } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - res := tc.Link.DatasetSchemaField() - assert.Equal(tt, tc.Expected, res) - }) - } -} - -func TestLink_Value(t *testing.T) { - dsid1 := id.NewDatasetSchemaID() - did1 := id.NewDatasetID() - dfid1 := id.NewDatasetSchemaFieldID() - dsf := []*dataset.Field{ - dataset.NewField(dfid1, dataset.ValueTypeString.ValueFrom("aaa"), ""), - } - - testCases := []struct { - Name string - Link *Link - Input *dataset.Dataset - Expected *dataset.Value - }{ - { - Name: "nil link", - }, - { - Name: "success", - Link: NewLink(did1, dsid1, dfid1), - Input: dataset.New().ID(did1).Schema(dsid1).Fields([]*dataset.Field{}).MustBuild(), - }, - { - Name: "success", - Link: NewLink(did1, dsid1, dfid1), - Input: dataset.New().ID(did1).Schema(dsid1).Fields(dsf).MustBuild(), - Expected: dataset.ValueTypeString.ValueFrom("aaa"), - }, - } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - res := tc.Link.Value(tc.Input) - assert.Equal(tt, tc.Expected, res) - }) - } -} -func TestLink_Validate(t *testing.T) { - dsid1 := id.NewDatasetSchemaID() - did1 := id.NewDatasetID() - dfid1 := id.NewDatasetSchemaFieldID() - - testCases := []struct { - Name string - DS *dataset.Dataset - DSS *dataset.Schema - Link *Link - Expected bool - }{ - { - Name: "nil links", - Expected: false, - }, - { - Name: "input schema id != link schema", - DS: dataset.New().ID(did1).Schema(dsid1).Fields([]*dataset.Field{ - dataset.NewField(dfid1, dataset.ValueTypeString.ValueFrom("vvv"), "")}).MustBuild(), - DSS: dataset.NewSchema().NewID().Fields([]*dataset.SchemaField{ - dataset.NewSchemaField(). - ID(dfid1). - Ref(dsid1.Ref()).Type(dataset.ValueTypeString). - MustBuild(), - }).MustBuild(), - Link: NewLink(did1, dsid1, dfid1), - Expected: false, - }, - { - Name: "nil input dataset", - DSS: dataset.NewSchema().ID(dsid1).Fields([]*dataset.SchemaField{ - dataset.NewSchemaField(). - ID(dfid1). - Ref(dsid1.Ref()).Type(dataset.ValueTypeString). - MustBuild(), - }).MustBuild(), - Link: NewLink(did1, dsid1, dfid1), - Expected: false, - }, - { - Name: "nil dataset field", - DS: dataset.New().ID(did1).Schema(dsid1).Fields([]*dataset.Field{}).MustBuild(), - DSS: dataset.NewSchema().ID(dsid1).Fields([]*dataset.SchemaField{ - dataset.NewSchemaField(). - ID(dfid1). - Ref(dsid1.Ref()).Type(dataset.ValueTypeString). - MustBuild(), - }).MustBuild(), - Link: NewLink(did1, dsid1, dfid1), - Expected: false, - }, - { - Name: "valid", - DS: dataset.New().ID(did1).Schema(dsid1).Fields([]*dataset.Field{ - dataset.NewField(dfid1, dataset.ValueTypeString.ValueFrom("vvv"), "")}).MustBuild(), - DSS: dataset.NewSchema().ID(dsid1).Fields([]*dataset.SchemaField{ - dataset.NewSchemaField(). - ID(dfid1). - Ref(dsid1.Ref()).Type(dataset.ValueTypeString). - MustBuild(), - }).MustBuild(), - Link: NewLink(did1, dsid1, dfid1), - Expected: true, - }, - } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - res := tc.Link.Validate(tc.DSS, tc.DS) - assert.Equal(tt, tc.Expected, res) - }) - } -} - -func TestLink_Clone(t *testing.T) { - var l *Link - assert.Nil(t, l.Clone()) - l = NewLink(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) - assert.Equal(t, l, l.Clone()) -} diff --git a/pkg/property/merged.go b/pkg/property/merged.go index 9b049c5b..a9e8e180 100644 --- a/pkg/property/merged.go +++ b/pkg/property/merged.go @@ -1,8 +1,6 @@ package property import ( - "context" - "github.com/reearth/reearth-backend/pkg/dataset" "github.com/reearth/reearth-backend/pkg/id" ) @@ -31,7 +29,7 @@ type MergedField struct { ID id.PropertySchemaFieldID Type ValueType Value *Value - Links *Links + Links *dataset.GraphPointer Overridden bool } @@ -57,7 +55,7 @@ func (m *MergedGroup) Datasets() []id.DatasetID { if f == nil { continue } - ids = append(ids, f.Links.DatasetIDs()...) + ids = append(ids, f.Links.Datasets()...) } return ids } @@ -100,13 +98,6 @@ func (m MergedMetadata) Merge(o *Property, p *Property) *Merged { return Merge(o, p, m.LinkedDataset) } -func (f *MergedField) DatasetValue(ctx context.Context, d dataset.GraphLoader) (*dataset.Value, error) { - if f == nil { - return nil, nil - } - return f.Links.DatasetValue(ctx, d) -} - // Merge merges two properties func Merge(o *Property, p *Property, linked *id.DatasetID) *Merged { if o == nil && p == nil || o != nil && p != nil && !o.Schema().Equal(p.Schema()) { @@ -274,14 +265,22 @@ func mergeField(original, parent *Field, linked *id.DatasetID) *MergedField { overridden = parent != nil } - var links *Links + var links *dataset.GraphPointer if l := original.Links(); l != nil { // original links are used but dataset is overrided - links = l.ApplyDataset(linked) + if linked != nil { + links = l.WithDataset(*linked) + } else { + links = l.Clone() + } overridden = parent != nil } else if l := parent.Links(); l != nil { // parent links are used and dataset is overrided - links = l.ApplyDataset(linked) + if linked != nil { + links = l.WithDataset(*linked) + } else { + links = l.Clone() + } } return &MergedField{ diff --git a/pkg/property/merged_test.go b/pkg/property/merged_test.go index e21e9606..ac4e5ef7 100644 --- a/pkg/property/merged_test.go +++ b/pkg/property/merged_test.go @@ -3,6 +3,7 @@ package property import ( "testing" + "github.com/reearth/reearth-backend/pkg/dataset" "github.com/reearth/reearth-backend/pkg/id" "github.com/stretchr/testify/assert" @@ -33,14 +34,14 @@ func TestMerge(t *testing.T) { fields1 := []*Field{ NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("a")).ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("a"))).Build(), NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("b")).ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("b"))).Build(), - NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("e")).ValueUnsafe(NewOptionalValue(ValueTypeString, nil)).LinksUnsafe(NewLinks([]*Link{NewLink(d2, ds, df)})).Build(), + NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("e")).ValueUnsafe(NewOptionalValue(ValueTypeString, nil)).LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d2, ds, df)})).Build(), NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("f")).ValueUnsafe(NewOptionalValue(ValueTypeNumber, nil)).Build(), } fields2 := []*Field{ NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("a")).ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("1"))).Build(), NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("c")).ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("2"))).Build(), - NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("d")).ValueUnsafe(NewOptionalValue(ValueTypeString, nil)).LinksUnsafe(NewLinks([]*Link{NewLinkFieldOnly(ds, df)})).Build(), + NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("d")).ValueUnsafe(NewOptionalValue(ValueTypeString, nil)).LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAtField(ds, df)})).Build(), NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("f")).ValueUnsafe(NewOptionalValue(ValueTypeString, nil)).Build(), } @@ -66,10 +67,10 @@ func TestMerge(t *testing.T) { sid := id.NewSceneID() op := New().ID(opid).Scene(sid).Schema(psid).Items(items1).MustBuild() - pp := New().NewID().Scene(sid).Schema(psid2).MustBuild() - pp2 := New().ID(ppid).Scene(sid).Schema(psid).Items(items2).MustBuild() + ppempty := New().NewID().Scene(sid).Schema(psid2).MustBuild() + pp := New().ID(ppid).Scene(sid).Schema(psid).Items(items2).MustBuild() - // Merge(op, pp2, &d) + // Merge(op, pp, &d) expected1 := &Merged{ Original: opid.Ref(), Parent: ppid.Ref(), @@ -100,7 +101,7 @@ func TestMerge(t *testing.T) { }, { ID: id.PropertySchemaFieldID("e"), - Links: NewLinks([]*Link{NewLink(d2, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d2, ds, df)}), Type: ValueTypeString, }, { @@ -130,7 +131,7 @@ func TestMerge(t *testing.T) { }, { ID: id.PropertySchemaFieldID("e"), - Links: NewLinks([]*Link{NewLink(d2, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d2, ds, df)}), Type: ValueTypeString, }, { @@ -140,7 +141,7 @@ func TestMerge(t *testing.T) { }, { ID: id.PropertySchemaFieldID("d"), - Links: NewLinks([]*Link{NewLink(d, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d, ds, df)}), Type: ValueTypeString, }, }, @@ -163,7 +164,7 @@ func TestMerge(t *testing.T) { }, { ID: id.PropertySchemaFieldID("e"), - Links: NewLinks([]*Link{NewLink(d2, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d2, ds, df)}), Type: ValueTypeString, }, { @@ -190,7 +191,7 @@ func TestMerge(t *testing.T) { }, { ID: id.PropertySchemaFieldID("d"), - Links: NewLinks([]*Link{NewLink(d, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d, ds, df)}), Type: ValueTypeString, }, { @@ -233,7 +234,7 @@ func TestMerge(t *testing.T) { }, { ID: id.PropertySchemaFieldID("e"), - Links: NewLinks([]*Link{NewLink(d2, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d2, ds, df)}), Type: ValueTypeString, }, { @@ -262,7 +263,7 @@ func TestMerge(t *testing.T) { }, { ID: id.PropertySchemaFieldID("e"), - Links: NewLinks([]*Link{NewLink(d2, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d2, ds, df)}), Type: ValueTypeString, }, { @@ -289,7 +290,7 @@ func TestMerge(t *testing.T) { }, { ID: id.PropertySchemaFieldID("e"), - Links: NewLinks([]*Link{NewLink(d2, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d2, ds, df)}), Type: ValueTypeString, }, { @@ -301,7 +302,7 @@ func TestMerge(t *testing.T) { }, } - // Merge(nil, pp2, &d) + // Merge(nil, pp, &d) expected3 := &Merged{ Original: nil, Parent: ppid.Ref(), @@ -332,7 +333,7 @@ func TestMerge(t *testing.T) { }, { ID: id.PropertySchemaFieldID("d"), - Links: NewLinks([]*Link{NewLink(d, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d, ds, df)}), Type: ValueTypeString, }, { @@ -361,7 +362,7 @@ func TestMerge(t *testing.T) { }, { ID: id.PropertySchemaFieldID("d"), - Links: NewLinks([]*Link{NewLink(d, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d, ds, df)}), Type: ValueTypeString, }, { @@ -388,7 +389,7 @@ func TestMerge(t *testing.T) { }, { ID: id.PropertySchemaFieldID("d"), - Links: NewLinks([]*Link{NewLink(d, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d, ds, df)}), Type: ValueTypeString, }, { @@ -400,14 +401,54 @@ func TestMerge(t *testing.T) { }, } - merged0 := Merge(nil, nil, nil) - assert.Nil(t, merged0) - merged1 := Merge(op, pp, nil) - assert.Nil(t, merged1) - merged2 := Merge(op, pp2, &d) - assert.Equal(t, expected1, merged2) - merged3 := Merge(op, nil, &d) - assert.Equal(t, expected2, merged3) - merged4 := Merge(nil, pp2, &d) - assert.Equal(t, expected3, merged4) + tests := []struct { + name string + o *Property + p *Property + l *id.DatasetID + want *Merged + }{ + { + name: "nil", + o: nil, + p: nil, + l: nil, + want: nil, + }, + { + name: "empty parent", + o: op, + p: ppempty, + l: nil, + want: nil, + }, + { + name: "ok", + o: op, + p: pp, + l: &d, + want: expected1, + }, + { + name: "original only", + o: op, + p: nil, + l: &d, + want: expected2, + }, + { + name: "parent only", + o: nil, + p: pp, + l: &d, + want: expected3, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := Merge(tt.o, tt.p, tt.l) + assert.Equal(t, tt.want, actual) + }) + } } diff --git a/pkg/property/migrator.go b/pkg/property/migrator.go index b060d47c..9e38d6d0 100644 --- a/pkg/property/migrator.go +++ b/pkg/property/migrator.go @@ -1,5 +1,11 @@ package property +import ( + "context" + + "github.com/reearth/reearth-backend/pkg/dataset" +) + type Migrator struct { NewSchema *Schema Plans []MigrationPlan @@ -13,3 +19,69 @@ type MigrationPlan struct { // func (m Migrator) Migrate(from *Property) *Property { // } + +type DatasetMigrator struct { + m *dataset.Migrator + l dataset.GraphLoader +} + +func NewDatasetMigrator(m *dataset.Migrator, l dataset.GraphLoader) *DatasetMigrator { + return &DatasetMigrator{ + m: m, + l: l, + } +} + +func (m *DatasetMigrator) MigrateProperty(ctx context.Context, p *Property) error { + if m == nil { + return nil + } + for _, i := range p.Items() { + if g := ToGroup(i); g != nil { + if err := m.MigrateGroup(ctx, g); err != nil { + return err + } + } else if l := ToGroupList(i); l != nil { + if err := m.MigrateGroupList(ctx, l); err != nil { + return err + } + } + } + return nil +} + +func (m *DatasetMigrator) MigrateGroupList(ctx context.Context, g *GroupList) error { + if m == nil { + return nil + } + for _, g := range g.Groups() { + if err := m.MigrateGroup(ctx, g); err != nil { + return err + } + } + return nil +} + +func (m *DatasetMigrator) MigrateGroup(ctx context.Context, g *Group) error { + if m == nil { + return nil + } + for _, f := range g.Fields() { + if err := m.MigrateField(ctx, f); err != nil { + return err + } + } + return nil +} + +func (m *DatasetMigrator) MigrateField(ctx context.Context, f *Field) error { + if m == nil { + return nil + } + nl, err := m.m.MigrateAndValidateGraphPointer(ctx, f.Links(), m.l) + if err != nil { + return err + } + f.Link(nl) + return nil +} diff --git a/pkg/property/property.go b/pkg/property/property.go index 1fbbb2eb..497dda2a 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -440,9 +440,9 @@ func (p *Property) AutoLinkField(s *Schema, v ValueType, d id.DatasetSchemaID, d f, _, _, ok := p.GetOrCreateField(s, ptr) if ok { if ds == nil { - f.Link(NewLinks([]*Link{NewLinkFieldOnly(d, *df)})) + f.Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAtField(d, *df)})) } else { - f.Link(NewLinks([]*Link{NewLink(*ds, d, *df)})) + f.Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(*ds, d, *df)})) } } } @@ -461,16 +461,6 @@ func (p *Property) MigrateSchema(ctx context.Context, newSchema *Schema, dl data p.Prune() } -func (p *Property) MigrateDataset(q DatasetMigrationParam) { - if p == nil { - return - } - for _, f := range p.items { - f.MigrateDataset(q) - } - p.Prune() -} - func (p *Property) ValidateSchema(ps *Schema) error { if p == nil { return nil diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index 153a1cdc..8b375104 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -69,14 +69,14 @@ func TestPropertyMigrateSchema(t *testing.T) { Build(), // should remain NewFieldUnsafe().FieldUnsafe(schemaField5ID). - LinksUnsafe(NewLinks([]*Link{ - NewLink(datasetID, datasetSchemaID, datasetFieldID), + LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{ + dataset.PointAt(datasetID, datasetSchemaID, datasetFieldID), })). Build(), // should be removed because of linked dataset field value type NewFieldUnsafe().FieldUnsafe(schemaField6ID). - LinksUnsafe(NewLinks([]*Link{ - NewLink(datasetID, datasetSchemaID, datasetFieldID), + LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{ + dataset.PointAt(datasetID, datasetSchemaID, datasetFieldID), })). Build(), // should be removed because of type diff --git a/pkg/property/sealed.go b/pkg/property/sealed.go index 2279ad0c..ae773d02 100644 --- a/pkg/property/sealed.go +++ b/pkg/property/sealed.go @@ -103,12 +103,16 @@ func sealedGroupList(ctx context.Context, gl []*MergedGroup, d dataset.GraphLoad func sealedGroup(ctx context.Context, fields []*MergedField, d dataset.GraphLoader) ([]*SealedField, error) { res := []*SealedField{} for _, f := range fields { - dv, err := f.DatasetValue(ctx, d) - if err != nil { - return nil, err + var dv *dataset.Value + if f.Links != nil { + _, df, err := d.ByGraphPointer(ctx, f.Links) + if err != nil { + return nil, err + } + dv = df.Value().Clone() } - if val := NewValueAndDatasetValue(f.Type, dv.Clone(), f.Value.Clone()); val != nil { + if val := NewValueAndDatasetValue(f.Type, dv, f.Value.Clone()); val != nil { res = append(res, &SealedField{ ID: f.ID, Val: val, diff --git a/pkg/property/sealed_test.go b/pkg/property/sealed_test.go index 209856c8..e9658763 100644 --- a/pkg/property/sealed_test.go +++ b/pkg/property/sealed_test.go @@ -64,7 +64,7 @@ func TestSeal(t *testing.T) { { ID: id.PropertySchemaFieldID("b"), Value: ValueTypeString.ValueFrom("b"), - Links: NewLinks([]*Link{NewLink(d, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d, ds, df)}), Type: ValueTypeString, }, }, @@ -85,7 +85,7 @@ func TestSeal(t *testing.T) { { ID: id.PropertySchemaFieldID("b"), Value: ValueTypeString.ValueFrom("aaa"), - Links: NewLinks([]*Link{NewLink(d, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d, ds, df)}), Type: ValueTypeString, }, }, @@ -243,7 +243,7 @@ func TestSealedItemFrom(t *testing.T) { { ID: id.PropertySchemaFieldID("b"), Value: ValueTypeString.ValueFrom("b"), - Links: NewLinks([]*Link{NewLink(d, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d, ds, df)}), Type: ValueTypeString, }, }, @@ -310,7 +310,7 @@ func TestSealedItemFrom(t *testing.T) { { ID: id.PropertySchemaFieldID("b"), Value: ValueTypeString.ValueFrom("aaa"), - Links: NewLinks([]*Link{NewLink(d, ds, df)}), + Links: dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d, ds, df)}), Type: ValueTypeString, }, }, diff --git a/pkg/property/value_dataset.go b/pkg/property/value_dataset.go index 3443ad0f..30abe1b9 100644 --- a/pkg/property/value_dataset.go +++ b/pkg/property/value_dataset.go @@ -57,7 +57,8 @@ func (v *ValueAndDatasetValue) Value() *Value { return nil } if v.d != nil { - return valueFromDataset(v.d) + dv := valueFromDataset(v.d) + return dv } return v.p } diff --git a/pkg/scene/builder/builder_test.go b/pkg/scene/builder/builder_test.go index dc240799..75a79070 100644 --- a/pkg/scene/builder/builder_test.go +++ b/pkg/scene/builder/builder_test.go @@ -163,9 +163,9 @@ func TestSceneBuilder(t *testing.T) { property.NewFieldUnsafe(). FieldUnsafe(propertySchemaField1ID). ValueUnsafe(property.NewOptionalValue(property.ValueTypeString, nil)). - LinksUnsafe(property.NewLinks([]*property.Link{ - property.NewLink(ds2id, dss2id, ds2f1), - property.NewLink(ds3id, dss3id, ds3f1), + LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{ + dataset.PointAt(ds2id, dss2id, ds2f1), + dataset.PointAt(ds3id, dss3id, ds3f1), })). Build(), }).MustBuild(), @@ -222,8 +222,8 @@ func TestSceneBuilder(t *testing.T) { property.NewFieldUnsafe(). FieldUnsafe(propertySchemaField1ID). ValueUnsafe(property.NewOptionalValue(property.ValueTypeString, nil)). - LinksUnsafe(property.NewLinks([]*property.Link{ - property.NewLinkFieldOnly(dss3id, ds3f1), + LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{ + dataset.PointAtField(dss3id, ds3f1), })). Build(), property.NewFieldUnsafe(). @@ -259,8 +259,8 @@ func TestSceneBuilder(t *testing.T) { property.NewFieldUnsafe(). FieldUnsafe(propertySchemaField1ID). ValueUnsafe(property.NewOptionalValue(property.ValueTypeString, nil)). - LinksUnsafe(property.NewLinks([]*property.Link{ - property.NewLinkFieldOnly(dss1id, ds1f2), + LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{ + dataset.PointAtField(dss1id, ds1f2), })). Build(), }).MustBuild(), @@ -284,19 +284,19 @@ func TestSceneBuilder(t *testing.T) { property.NewFieldUnsafe(). FieldUnsafe(propertySchemaField1ID). ValueUnsafe(property.NewOptionalValue(property.ValueTypeString, nil)). - LinksUnsafe(property.NewLinks([]*property.Link{ - property.NewLinkFieldOnly(dss1id, ds1f1), - property.NewLinkFieldOnly(dss2id, ds2f1), - property.NewLinkFieldOnly(dss3id, ds3f1), + LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{ + dataset.PointAtField(dss1id, ds1f1), + dataset.PointAtField(dss2id, ds2f1), + dataset.PointAtField(dss3id, ds3f1), })). Build(), property.NewFieldUnsafe(). FieldUnsafe(propertySchemaField2ID). ValueUnsafe(property.NewOptionalValue(property.ValueTypeString, nil)). - LinksUnsafe(property.NewLinks([]*property.Link{ - property.NewLinkFieldOnly(dss1id, ds1f1), - property.NewLinkFieldOnly(dss2id, ds2f1), - property.NewLinkFieldOnly(dss3id, ds3f1), + LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{ + dataset.PointAtField(dss1id, ds1f1), + dataset.PointAtField(dss2id, ds2f1), + dataset.PointAtField(dss3id, ds3f1), })). Build(), }).MustBuild(), diff --git a/pkg/scene/sceneops/dataset_migrator.go b/pkg/scene/sceneops/dataset_migrator.go index c84303b9..7142bd42 100644 --- a/pkg/scene/sceneops/dataset_migrator.go +++ b/pkg/scene/sceneops/dataset_migrator.go @@ -37,118 +37,51 @@ func (r MigrateDatasetResult) Merge(r2 MigrateDatasetResult) MigrateDatasetResul } } -// NOTE: DatasetSchemaの削除には対応していない(自動的に削除されない) func (srv DatasetMigrator) Migrate(ctx context.Context, sid id.SceneID, newdsl []*dataset.Schema, newdl dataset.List) (MigrateDatasetResult, error) { scenes := []id.SceneID{sid} result := MigrateDatasetResult{} - // 削除対象 - noLogerUsedDS := []id.DatasetSchemaID{} - noLogerUsedD := []id.DatasetID{} - - // 古いDatasetSchema - oldDatasetSchemaMap := map[id.DatasetSchemaID]*dataset.Schema{} - // 新しいDatasetSchema - newDatasetSchemaMap := map[id.DatasetSchemaID]*dataset.Schema{} - // 新しいDatasetSchemaから古いDatasetSchemaIDへの対応 - datasetSchemaMapNewOld := map[id.DatasetSchemaID]id.DatasetSchemaID{} - // 古いDatasetSchemaから新しいDatasetSchemaIDへの対応 - datasetSchemaMapOldNew := map[id.DatasetSchemaID]id.DatasetSchemaID{} - // 古いDatasetFieldIDから新しいDatasetSchemaFieldIDへの対応 - datasetSchemaFieldIDMap := map[id.DatasetSchemaFieldID]id.DatasetSchemaFieldID{} - // 古いDatasetから新しいDatasetへの対応 - newDatasetMap := map[id.DatasetID]*dataset.Dataset{} - datasetMapOldNew := map[id.DatasetID]*dataset.Dataset{} - datasetIDMapOldNew := map[id.DatasetID]id.DatasetID{} - // 新しいDatasetSchemaからDatasetDiffへの対応 - datasetDiffMap := map[id.DatasetSchemaID]dataset.Diff{} - - // マップの作成 - for _, newds := range newdsl { - newDatasetSchemaMap[newds.ID()] = newds - - // ソース元が同じ古いDSを取得 - olddsl, err := srv.DatasetSchemaRepo.FindBySceneAndSource(ctx, sid, newds.Source()) - if err != nil { - return MigrateDatasetResult{}, err - } - - // 古いデータセットを探す(新しく追加されたものも入り込んでいるので) - var oldds *dataset.Schema - for _, o := range olddsl { - if o.ID() != newds.ID() { - oldds = o - } - } - if oldds == nil { - // ないならリンクされているレイヤーやプロパティも作成されていないはずなので無視 - continue - } - - oldDatasetSchemaMap[oldds.ID()] = oldds - datasetSchemaMapNewOld[newds.ID()] = oldds.ID() - datasetSchemaMapOldNew[oldds.ID()] = newds.ID() - - // フィールドの差分を取る - fieldDiff := oldds.FieldDiffBySource(newds) - for of, f := range fieldDiff.Replaced { - datasetSchemaFieldIDMap[of] = f.ID() - } - - // 古いDSのDを探し出す - olddl, _, err := srv.DatasetRepo.FindBySchema(ctx, oldds.ID(), scenes, nil) - if err != nil { - return MigrateDatasetResult{}, err - } - - // 削除対象に追加 - noLogerUsedDS = append(noLogerUsedDS, oldds.ID()) - for _, oldd := range olddl { - noLogerUsedD = append(noLogerUsedD, oldd.ID()) - } - - // 新しいDSのDのみ抽出 - currentNewdl := newdl.FilterByDatasetSchema(newds.ID()) - - // データセットの差分をとる - diff := dataset.List(olddl).DiffBySource(currentNewdl) - datasetDiffMap[newds.ID()] = diff - for od, d := range diff.Others { - datasetMapOldNew[od] = d - datasetIDMapOldNew[od] = d.ID() - newDatasetMap[d.ID()] = d - } + mm, err := dataset.NewMigrationMap( + newdsl, + newdl, + func(s *dataset.Schema) (dataset.SchemaList, error) { + return srv.DatasetSchemaRepo.FindBySceneAndSource(ctx, sid, s.Source()) + }, + func(s *dataset.Schema) (dataset.List, error) { + olddl, _, err := srv.DatasetRepo.FindBySchema(ctx, s.ID(), scenes, nil) + return olddl, err + }, + ) + if err != nil { + return MigrateDatasetResult{}, err } - // プロパティのマイグレーション + dm := property.NewDatasetMigrator(mm.Migrator(), dataset.GraphLoaderFromMap(newdl.Map())) + propeties, err := srv.PropertyRepo.FindLinkedAll(ctx, sid) if err != nil { return MigrateDatasetResult{}, err } + for _, p := range propeties { - p.MigrateDataset(property.DatasetMigrationParam{ - OldDatasetSchemaMap: datasetSchemaMapOldNew, - OldDatasetMap: datasetIDMapOldNew, - DatasetFieldIDMap: datasetSchemaFieldIDMap, - NewDatasetSchemaMap: newDatasetSchemaMap, - NewDatasetMap: newDatasetMap, - }) + if err := dm.MigrateProperty(ctx, p); err != nil { + return MigrateDatasetResult{}, err + } } + result.Properties = propeties.Map() - // 新しいDSでループ for _, newds := range newdsl { - oldds := oldDatasetSchemaMap[datasetSchemaMapNewOld[newds.ID()]] + oldds := mm.OldSchema(newds.ID()) if oldds == nil { - // リンクされているレイヤーやプロパティも作成されていないはずなので無視 continue } - diff, ok := datasetDiffMap[newds.ID()] + + diff, ok := mm.Diff[newds.ID()] if !ok { continue } - // レイヤーのマイグレーション result2, err := srv.migrateLayer(ctx, sid, oldds, newds, diff) if err != nil { return MigrateDatasetResult{}, err @@ -157,12 +90,12 @@ func (srv DatasetMigrator) Migrate(ctx context.Context, sid id.SceneID, newdsl [ result = result.Merge(result2) } - result.RemovedDatasetSchemas = append(result.RemovedDatasetSchemas, noLogerUsedDS...) - result.RemovedDatasets = append(result.RemovedDatasets, noLogerUsedD...) + result.RemovedDatasetSchemas = append(result.RemovedDatasetSchemas, mm.DeletedSchemas.All()...) + result.RemovedDatasets = append(result.RemovedDatasets, mm.Deleted.All()...) return result, nil } -func (srv DatasetMigrator) migrateLayer(ctx context.Context, sid id.SceneID, oldds *dataset.Schema, newds *dataset.Schema, diff dataset.Diff) (MigrateDatasetResult, error) { +func (srv DatasetMigrator) migrateLayer(ctx context.Context, sid id.SceneID, oldds, newds *dataset.Schema, diff dataset.Diff) (MigrateDatasetResult, error) { scenes := []id.SceneID{sid} // 前のデータセットスキーマに紐づいたレイヤーグループを取得 From 19220060b376dd37f1fb712165c398151831a505 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 6 Dec 2021 17:40:36 +0900 Subject: [PATCH 06/55] add cast method to property.Value, change value.Optional.Cast, add tests --- pkg/property/value.go | 11 ++ pkg/property/value_test.go | 262 +++++++++++++++++++++++++++++++++++++ pkg/value/optional.go | 6 +- pkg/value/optional_test.go | 2 +- 4 files changed, 275 insertions(+), 6 deletions(-) diff --git a/pkg/property/value.go b/pkg/property/value.go index 35404a98..df1654e8 100644 --- a/pkg/property/value.go +++ b/pkg/property/value.go @@ -89,6 +89,17 @@ func (v *Value) Interface() interface{} { return v.v.Interface() } +func (v *Value) Cast(vt ValueType) *Value { + if v == nil { + return nil + } + nv := v.v.Cast(value.Type(vt), types) + if nv == nil { + return nil + } + return &Value{v: *nv} +} + func (v *Value) ValueBool() *bool { if v == nil { return nil diff --git a/pkg/property/value_test.go b/pkg/property/value_test.go index a51528a3..236033bf 100644 --- a/pkg/property/value_test.go +++ b/pkg/property/value_test.go @@ -4,9 +4,223 @@ import ( "testing" "github.com/reearth/reearth-backend/pkg/dataset" + "github.com/reearth/reearth-backend/pkg/value" "github.com/stretchr/testify/assert" ) +func TestValue_IsEmpty(t *testing.T) { + tests := []struct { + name string + value *Value + want bool + }{ + { + name: "empty", + want: true, + }, + { + name: "nil", + want: true, + }, + { + name: "non-empty", + value: ValueTypeString.ValueFrom("foo"), + want: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.value.IsEmpty()) + }) + } +} + +func TestValue_Clone(t *testing.T) { + tests := []struct { + name string + value *Value + want *Value + }{ + { + name: "ok", + value: ValueTypeString.ValueFrom("foo"), + want: &Value{ + v: *value.TypeString.ValueFrom("foo", types), + }, + }, + { + name: "nil", + value: nil, + want: nil, + }, + { + name: "empty", + value: &Value{}, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.value.Clone()) + }) + } +} + +func TestValue_Value(t *testing.T) { + tests := []struct { + name string + value *Value + want interface{} + }{ + { + name: "ok", + value: ValueTypeString.ValueFrom("foo"), + want: "foo", + }, + { + name: "empty", + value: &Value{}, + }, + { + name: "nil", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if tt.want == nil { + assert.Nil(t, tt.value.Value()) + } else { + assert.Equal(t, tt.want, tt.value.Value()) + } + }) + } +} + +func TestValue_Type(t *testing.T) { + tests := []struct { + name string + value *Value + want ValueType + }{ + { + name: "ok", + value: ValueTypeString.ValueFrom("foo"), + want: ValueTypeString, + }, + { + name: "empty", + value: &Value{}, + want: ValueTypeUnknown, + }, + { + name: "nil", + want: ValueTypeUnknown, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.value.Type()) + }) + } +} + +func TestValue_Interface(t *testing.T) { + tests := []struct { + name string + value *Value + want interface{} + }{ + { + name: "string", + value: ValueTypeString.ValueFrom("foo"), + want: "foo", + }, + { + name: "empty", + value: &Value{}, + want: nil, + }, + { + name: "nil", + value: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.value.Interface()) + }) + } +} + +func TestValue_Cast(t *testing.T) { + type args struct { + t ValueType + } + tests := []struct { + name string + target *Value + args args + want *Value + }{ + { + name: "diff type", + target: ValueTypeNumber.ValueFrom(1.1), + args: args{t: ValueTypeString}, + want: ValueTypeString.ValueFrom("1.1"), + }, + { + name: "same type", + target: ValueTypeNumber.ValueFrom(1.1), + args: args{t: ValueTypeNumber}, + want: ValueTypeNumber.ValueFrom(1.1), + }, + { + name: "failed to cast", + target: ValueTypeLatLng.ValueFrom(LatLng{Lat: 1, Lng: 2}), + args: args{t: ValueTypeString}, + want: nil, + }, + { + name: "invalid type", + target: ValueTypeNumber.ValueFrom(1.1), + args: args{t: ValueTypeUnknown}, + want: nil, + }, + { + name: "empty", + target: &Value{}, + args: args{t: ValueTypeString}, + want: nil, + }, + { + name: "nil", + target: nil, + args: args{t: ValueTypeString}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Cast(tt.args.t)) + }) + } +} + func TestValueFromDataset(t *testing.T) { testCases := []struct { Name string @@ -62,3 +276,51 @@ func TestValueFromDataset(t *testing.T) { }) } } + +func TestValueFromStringOrNumber(t *testing.T) { + type args struct { + s string + } + tests := []struct { + name string + args args + want *Value + }{ + { + name: "string", + args: args{"aax"}, + want: ValueTypeString.ValueFrom("aax"), + }, + { + name: "number positive int", + args: args{"1023"}, + want: ValueTypeNumber.ValueFrom(1023), + }, + { + name: "number negative int", + args: args{"-1"}, + want: ValueTypeNumber.ValueFrom(-1), + }, + { + name: "number float", + args: args{"1.14"}, + want: ValueTypeNumber.ValueFrom(1.14), + }, + { + name: "bool true", + args: args{"true"}, + want: ValueTypeBool.ValueFrom(true), + }, + { + name: "bool false", + args: args{"false"}, + want: ValueTypeBool.ValueFrom(false), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, ValueFromStringOrNumber(tt.args.s)) + }) + } +} diff --git a/pkg/value/optional.go b/pkg/value/optional.go index 0c6557ee..8bf0b084 100644 --- a/pkg/value/optional.go +++ b/pkg/value/optional.go @@ -60,7 +60,7 @@ func (ov *Optional) Clone() *Optional { } } -// Cast tries to convert the value to the new type and generates a new Optional. If cast was failed, it returns nil. +// Cast tries to convert the value to the new type and generates a new Optional. func (ov *Optional) Cast(t Type, p TypePropertyMap) *Optional { if ov == nil || ov.t == TypeUnknown { return nil @@ -70,9 +70,5 @@ func (ov *Optional) Cast(t Type, p TypePropertyMap) *Optional { } nv := ov.v.Cast(t, p) - if nv == nil { - return nil // failed to cast - } - return NewOptional(t, nv) } diff --git a/pkg/value/optional_test.go b/pkg/value/optional_test.go index ef5365fd..9c05d2cc 100644 --- a/pkg/value/optional_test.go +++ b/pkg/value/optional_test.go @@ -362,7 +362,7 @@ func TestOptional_Cast(t *testing.T) { name: "failed to cast", target: &Optional{t: TypeLatLng, v: TypeLatLng.ValueFrom(LatLng{Lat: 1, Lng: 2}, nil)}, args: args{t: TypeString}, - want: nil, + want: &Optional{t: TypeString}, }, { name: "empty", From 1411aa4254407e20eb7c936e1a9772e5f7cefa77 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 6 Dec 2021 17:43:30 +0900 Subject: [PATCH 07/55] add property id --- pkg/property/id.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 pkg/property/id.go diff --git a/pkg/property/id.go b/pkg/property/id.go new file mode 100644 index 00000000..110316ba --- /dev/null +++ b/pkg/property/id.go @@ -0,0 +1,27 @@ +package property + +import "github.com/reearth/reearth-backend/pkg/id" + +type ID = id.PropertyID +type ItemID = id.PropertyItemID +type FieldID = id.PropertySchemaFieldID +type SchemaID = id.PropertySchemaID +type SchemaGroupID = id.PropertySchemaGroupID + +type IDSet = id.PropertyIDSet +type ItemIDSet = id.PropertyItemIDSet + +var NewID = id.NewPropertyID +var NewItemID = id.NewPropertyItemID + +var IDFrom = id.PropertyIDFrom +var SchemaIDFrom = id.PropertySchemaIDFrom +var FieldIDFrom = id.PropertySchemaFieldIDFrom +var ItemIDFrom = id.PropertyItemIDFrom + +var MustID = id.MustPropertyID +var MustSchemaID = id.MustPropertySchemaID +var MustItemID = id.MustPropertyItemID + +var NewIDSet = id.NewPropertyIDSet +var NewItemIDSet = id.NewPropertyItemIDSet From 66eecf29ef8810e015f8ba2434851306b837bc32 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 6 Dec 2021 19:23:19 +0900 Subject: [PATCH 08/55] enhance value converting --- pkg/property/value.go | 13 ++-- pkg/property/value_optional_test.go | 2 +- pkg/value/bool.go | 22 +++++-- pkg/value/bool_test.go | 61 ++++++++++++++++++ pkg/value/latlng.go | 13 +++- pkg/value/latlngheight.go | 16 +++-- pkg/value/number.go | 15 ++++- pkg/value/number_test.go | 99 +++++++++++++++++++++++++++++ pkg/value/string.go | 9 ++- pkg/value/string_test.go | 49 ++++++++++++++ 10 files changed, 274 insertions(+), 25 deletions(-) create mode 100644 pkg/value/bool_test.go create mode 100644 pkg/value/number_test.go create mode 100644 pkg/value/string_test.go diff --git a/pkg/property/value.go b/pkg/property/value.go index df1654e8..636ad4c6 100644 --- a/pkg/property/value.go +++ b/pkg/property/value.go @@ -2,7 +2,6 @@ package property import ( "net/url" - "strconv" "github.com/reearth/reearth-backend/pkg/value" ) @@ -211,16 +210,12 @@ func (v *Value) ValuePolygon() *Polygon { } func ValueFromStringOrNumber(s string) *Value { - if vint, err := strconv.Atoi(s); err == nil { - return ValueTypeNumber.ValueFrom(vint) + if s == "true" || s == "false" || s == "TRUE" || s == "FALSE" || s == "True" || s == "False" { + return ValueTypeBool.ValueFrom(s) } - if vfloat64, err := strconv.ParseFloat(s, 64); err == nil { - return ValueTypeNumber.ValueFrom(vfloat64) - } - - if vbool, err := strconv.ParseBool(s); err == nil { - return ValueTypeBool.ValueFrom(vbool) + if v := ValueTypeNumber.ValueFrom(s); v != nil { + return v } return ValueTypeString.ValueFrom(s) diff --git a/pkg/property/value_optional_test.go b/pkg/property/value_optional_test.go index 6b1710b4..f73f4970 100644 --- a/pkg/property/value_optional_test.go +++ b/pkg/property/value_optional_test.go @@ -328,7 +328,7 @@ func TestOptionalValue_Cast(t *testing.T) { name: "failed to cast", target: &OptionalValue{ov: *value.OptionalFrom(value.TypeLatLng.ValueFrom(LatLng{Lat: 1, Lng: 2}, types))}, args: args{t: ValueTypeString}, - want: nil, + want: &OptionalValue{ov: *value.NewOptional(value.TypeString, nil)}, }, { name: "empty", diff --git a/pkg/value/bool.go b/pkg/value/bool.go index 538e3f5f..70a31278 100644 --- a/pkg/value/bool.go +++ b/pkg/value/bool.go @@ -1,15 +1,29 @@ package value +import "strconv" + var TypeBool Type = "bool" type propertyBool struct{} func (*propertyBool) I2V(i interface{}) (interface{}, bool) { - if v, ok := i.(bool); ok { + switch v := i.(type) { + case bool: return v, true - } - if v, ok := i.(*bool); ok && v != nil { - return *v, true + case string: + if b, err := strconv.ParseBool(v); err == nil { + return b, true + } + case *bool: + if v != nil { + return *v, true + } + case *string: + if v != nil { + if b, err := strconv.ParseBool(*v); err == nil { + return b, true + } + } } return nil, false } diff --git a/pkg/value/bool_test.go b/pkg/value/bool_test.go new file mode 100644 index 00000000..4b96481f --- /dev/null +++ b/pkg/value/bool_test.go @@ -0,0 +1,61 @@ +package value + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_propertyBool_I2V(t *testing.T) { + tr := true + fa := false + trs1 := "true" + trs2 := "TRUE" + trs3 := "True" + trs4 := "T" + trs5 := "t" + trs6 := "1" + fas1 := "false" + fas2 := "FALSE" + fas3 := "False" + fas4 := "F" + fas5 := "f" + fas6 := "0" + + tests := []struct { + name string + args []interface{} + want1 interface{} + want2 bool + }{ + { + name: "true", + args: []interface{}{tr, trs1, trs2, trs3, trs4, trs5, trs6, &tr, &trs1, &trs2, &trs3, &trs4, &trs5, &trs6}, + want1: true, + want2: true, + }, + { + name: "false", + args: []interface{}{fa, fas1, fas2, fas3, fas4, fas5, fas6, &fa, &fas1, &fas2, &fas3, &fas4, &fas5, &fas6}, + want1: false, + want2: true, + }, + { + name: "nil", + args: []interface{}{"foo", (*bool)(nil), (*string)(nil), nil}, + want1: nil, + want2: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &propertyBool{} + for i, v := range tt.args { + got1, got2 := p.I2V(v) + assert.Equal(t, tt.want1, got1, "test %d", i) + assert.Equal(t, tt.want2, got2, "test %d", i) + } + }) + } +} diff --git a/pkg/value/latlng.go b/pkg/value/latlng.go index 7612eb54..2bf97ab9 100644 --- a/pkg/value/latlng.go +++ b/pkg/value/latlng.go @@ -22,14 +22,21 @@ var TypeLatLng Type = "latlng" type propertyLatLng struct{} func (*propertyLatLng) I2V(i interface{}) (interface{}, bool) { - if v, ok := i.(LatLng); ok { + switch v := i.(type) { + case LatLng: return v, true - } else if v, ok := i.(*LatLng); ok { + case LatLngHeight: + return LatLng{Lat: v.Lat, Lng: v.Lng}, true + case *LatLng: if v != nil { return *v, true } - return nil, false + case *LatLngHeight: + if v != nil { + return LatLng{Lat: v.Lat, Lng: v.Lng}, true + } } + v := LatLng{} if err := mapstructure.Decode(i, &v); err != nil { return nil, false diff --git a/pkg/value/latlngheight.go b/pkg/value/latlngheight.go index 173f3875..f2120899 100644 --- a/pkg/value/latlngheight.go +++ b/pkg/value/latlngheight.go @@ -24,15 +24,19 @@ var TypeLatLngHeight Type = "latlngheight" type propertyLatLngHeight struct{} func (*propertyLatLngHeight) I2V(i interface{}) (interface{}, bool) { - if v, ok := i.(LatLngHeight); ok { + switch v := i.(type) { + case LatLngHeight: return v, true - } - - if v, ok := i.(*LatLngHeight); ok { + case LatLng: + return LatLngHeight{Lat: v.Lat, Lng: v.Lng, Height: 0}, true + case *LatLngHeight: + if v != nil { + return *v, true + } + case *LatLng: if v != nil { - return *v, false + return LatLngHeight{Lat: v.Lat, Lng: v.Lng, Height: 0}, true } - return nil, false } v := LatLngHeight{} diff --git a/pkg/value/number.go b/pkg/value/number.go index 275e5325..53ce8bfe 100644 --- a/pkg/value/number.go +++ b/pkg/value/number.go @@ -1,6 +1,9 @@ package value -import "encoding/json" +import ( + "encoding/json" + "strconv" +) var TypeNumber Type = "number" @@ -38,6 +41,10 @@ func (*propertyNumber) I2V(i interface{}) (interface{}, bool) { if f, err := v.Float64(); err == nil { return f, true } + case string: + if vfloat64, err := strconv.ParseFloat(v, 64); err == nil { + return vfloat64, true + } case *float64: if v != nil { return *v, true @@ -96,6 +103,12 @@ func (*propertyNumber) I2V(i interface{}) (interface{}, bool) { return f, true } } + case *string: + if v != nil { + if vfloat64, err := strconv.ParseFloat(*v, 64); err == nil { + return vfloat64, true + } + } } return nil, false } diff --git a/pkg/value/number_test.go b/pkg/value/number_test.go new file mode 100644 index 00000000..7ca44da5 --- /dev/null +++ b/pkg/value/number_test.go @@ -0,0 +1,99 @@ +package value + +import ( + "encoding/json" + "math" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_propertyNumber_I2V(t *testing.T) { + z1 := 0 + z2 := 0.0 + z3 := "0" + z4 := json.Number("0") + z5 := json.Number("-0") + n1 := 1.12 + n2 := "1.12" + n3 := json.Number("1.12") + nn1 := -0.11 + nn2 := "-0.11" + nn3 := json.Number("-0.11") + nan1 := math.NaN() + nan2 := json.Number("NaN") + inf1 := math.Inf(0) + inf2 := json.Number("Infinity") + infn1 := math.Inf(-1) + infn2 := json.Number("-Infinity") + + tests := []struct { + name string + args []interface{} + want1 interface{} + want2 bool + }{ + { + name: "zero", + args: []interface{}{z1, z2, z3, z4, z5, &z1, &z2, &z3, &z4, &z5}, + want1: 0.0, + want2: true, + }, + { + name: "float", + args: []interface{}{n1, n2, n3, &n1, &n2, &n3}, + want1: 1.12, + want2: true, + }, + { + name: "negative float", + args: []interface{}{nn1, nn2, nn3, &nn1, &nn2, &nn3}, + want1: -0.11, + want2: true, + }, + { + name: "nan", + args: []interface{}{nan1, nan2}, + want1: math.NaN(), + want2: true, + }, + { + name: "inf", + args: []interface{}{inf1, inf2}, + want1: math.Inf(0), + want2: true, + }, + { + name: "negative inf", + args: []interface{}{infn1, infn2}, + want1: math.Inf(-1), + want2: true, + }, + { + name: "nil", + args: []interface{}{"foo", (*float64)(nil), (*string)(nil), (*int)(nil), (*json.Number)(nil), nil}, + want1: nil, + want2: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &propertyNumber{} + for i, v := range tt.args { + got1, got2 := p.I2V(v) + if f, ok := tt.want1.(float64); ok { + if math.IsNaN(f) { + assert.True(t, math.IsNaN(tt.want1.(float64))) + } else { + assert.Equal(t, tt.want1, got1, "test %d", i) + } + } else { + assert.Equal(t, tt.want1, got1, "test %d", i) + } + + assert.Equal(t, tt.want2, got2, "test %d", i) + } + }) + } +} diff --git a/pkg/value/string.go b/pkg/value/string.go index 15341a42..df54e566 100644 --- a/pkg/value/string.go +++ b/pkg/value/string.go @@ -11,11 +11,18 @@ func (*propertyString) I2V(i interface{}) (interface{}, bool) { return v, true } if v, ok := i.(*string); ok { - return *v, true + if v != nil { + return *v, true + } } if v, ok := i.(float64); ok { return strconv.FormatFloat(v, 'f', -1, 64), true } + if v, ok := i.(*float64); ok { + if v != nil { + return strconv.FormatFloat(*v, 'f', -1, 64), true + } + } return nil, false } diff --git a/pkg/value/string_test.go b/pkg/value/string_test.go new file mode 100644 index 00000000..c28fc75e --- /dev/null +++ b/pkg/value/string_test.go @@ -0,0 +1,49 @@ +package value + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_propertyString_I2V(t *testing.T) { + s := "foobar" + n := 1.12 + + tests := []struct { + name string + args []interface{} + want1 interface{} + want2 bool + }{ + { + name: "string", + args: []interface{}{s, &s}, + want1: "foobar", + want2: true, + }, + { + name: "number", + args: []interface{}{n, &n}, + want1: "1.12", + want2: true, + }, + { + name: "nil", + args: []interface{}{(*string)(nil), nil}, + want1: nil, + want2: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &propertyString{} + for i, v := range tt.args { + got1, got2 := p.I2V(v) + assert.Equal(t, tt.want1, got1, "test %d", i) + assert.Equal(t, tt.want2, got2, "test %d", i) + } + }) + } +} From 76318e7a553f4c09f27ebcc7350d59ff5562fb4a Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 6 Dec 2021 19:23:57 +0900 Subject: [PATCH 09/55] add Cast to property.Field --- pkg/property/field.go | 8 +++++ pkg/property/field_test.go | 62 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/pkg/property/field.go b/pkg/property/field.go index b8d836ab..3ac05346 100644 --- a/pkg/property/field.go +++ b/pkg/property/field.go @@ -102,6 +102,14 @@ func (p *Field) Update(value *Value, field *SchemaField) error { return nil } +func (p *Field) Cast(t ValueType) { + if p == nil || p.Type() == t { + return + } + p.v = p.v.Cast(t) + p.Unlink() +} + func (p *Field) UpdateUnsafe(value *Value) { if p == nil { return diff --git a/pkg/property/field_test.go b/pkg/property/field_test.go index 225b1fee..a2a75ba1 100644 --- a/pkg/property/field_test.go +++ b/pkg/property/field_test.go @@ -125,3 +125,65 @@ func TestField_Update(t *testing.T) { b.UpdateUnsafe(v) assert.Equal(t, v, b.Value()) } + +func TestField_Cast(t *testing.T) { + dgp := dataset.NewGraphPointer([]*dataset.Pointer{ + dataset.PointAt(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()), + }) + + type args struct { + t ValueType + } + tests := []struct { + name string + target *Field + args args + want *Field + }{ + { + name: "ok", + target: &Field{ + field: FieldID("foobar"), + v: OptionalValueFrom(ValueTypeString.ValueFrom("-123")), + links: dgp.Clone(), + }, + args: args{t: ValueTypeNumber}, + want: &Field{ + field: FieldID("foobar"), + v: OptionalValueFrom(ValueTypeNumber.ValueFrom(-123)), + }, + }, + { + name: "failed", + target: &Field{ + field: FieldID("foobar"), + v: OptionalValueFrom(ValueTypeString.ValueFrom("foo")), + links: dgp.Clone(), + }, + args: args{t: ValueTypeLatLng}, + want: &Field{ + field: FieldID("foobar"), + v: NewOptionalValue(ValueTypeLatLng, nil), + }, + }, + { + name: "empty", + target: &Field{}, + args: args{t: ValueTypeNumber}, + want: &Field{}, + }, + { + name: "nil", + target: nil, + args: args{t: ValueTypeNumber}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.target.Cast(tt.args.t) + assert.Equal(t, tt.want, tt.target) + }) + } +} From 21501be85ba3469b44f585584bc3ff66e7fbb4df Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 7 Dec 2021 13:54:44 +0900 Subject: [PATCH 10/55] add GroupAndFields, GroupAndField to property.Schema --- pkg/property/schema.go | 35 +++- pkg/property/schema_field_test.go | 6 + pkg/property/schema_group_test.go | 5 + pkg/property/schema_test.go | 328 +++++++++++++++++++++++------- 4 files changed, 303 insertions(+), 71 deletions(-) diff --git a/pkg/property/schema.go b/pkg/property/schema.go index b14eaa04..71e14ac9 100644 --- a/pkg/property/schema.go +++ b/pkg/property/schema.go @@ -2,7 +2,6 @@ package property import "github.com/reearth/reearth-backend/pkg/id" -// Schema _ type Schema struct { id id.PropertySchemaID version int @@ -10,6 +9,11 @@ type Schema struct { linkable LinkableFields } +type SchemaGroupAndField struct { + Group *SchemaGroup + Field *SchemaField +} + type LinkableFields struct { LatLng *Pointer URL *Pointer @@ -114,6 +118,35 @@ func (p *Schema) GroupByPointer(ptr *Pointer) *SchemaGroup { return nil } +func (gf SchemaGroupAndField) IsEmpty() bool { + return gf.Group == nil && gf.Field == nil +} + +func (p *Schema) GroupAndFields() []SchemaGroupAndField { + if p == nil { + return nil + } + fields := []SchemaGroupAndField{} + for _, g := range p.groups { + for _, f := range g.Fields() { + fields = append(fields, SchemaGroupAndField{Group: g, Field: f}) + } + } + return fields +} + +func (p *Schema) GroupAndField(f FieldID) *SchemaGroupAndField { + if p == nil { + return nil + } + for _, g := range p.groups { + if gf := g.Field(f); gf != nil { + return &SchemaGroupAndField{Group: g, Field: gf} + } + } + return nil +} + func (s *Schema) DetectDuplicatedFields() []id.PropertySchemaFieldID { duplicated := []id.PropertySchemaFieldID{} ids := map[id.PropertySchemaFieldID]struct{}{} diff --git a/pkg/property/schema_field_test.go b/pkg/property/schema_field_test.go index e339c3e6..f7d4a399 100644 --- a/pkg/property/schema_field_test.go +++ b/pkg/property/schema_field_test.go @@ -7,6 +7,12 @@ import ( "github.com/stretchr/testify/assert" ) +var ( + testSchemaField1 = NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() + testSchemaField2 = NewSchemaField().ID("b").Type(ValueTypeNumber).MustBuild() + testSchemaField3 = NewSchemaField().ID("c").Type(ValueTypeLatLng).MustBuild() +) + func TestSchemaField_MinMax(t *testing.T) { getFloatRef := func(f float64) *float64 { return &f diff --git a/pkg/property/schema_group_test.go b/pkg/property/schema_group_test.go index 09b63522..0906328c 100644 --- a/pkg/property/schema_group_test.go +++ b/pkg/property/schema_group_test.go @@ -8,6 +8,11 @@ import ( "github.com/stretchr/testify/assert" ) +var ( + testSchemaGroup1 = NewSchemaGroup().ID("aa").Schema(testSchemaID).Fields([]*SchemaField{testSchemaField1, testSchemaField2}).MustBuild() + testSchemaGroup2 = NewSchemaGroup().ID("bb").Schema(testSchemaID).Fields([]*SchemaField{testSchemaField3}).IsList(true).MustBuild() +) + func TestSchemaGroup(t *testing.T) { scid := id.PropertySchemaGroupID("aa") sid := id.MustPropertySchemaID("xx~1.0.0/aa") diff --git a/pkg/property/schema_test.go b/pkg/property/schema_test.go index 6c712043..5cd3b51c 100644 --- a/pkg/property/schema_test.go +++ b/pkg/property/schema_test.go @@ -7,110 +7,266 @@ import ( "github.com/stretchr/testify/assert" ) -func TestSchema_Nil(t *testing.T) { - var s *Schema - assert.Nil(t, s.IDRef()) - assert.Nil(t, nil, s.Fields()) - assert.Nil(t, nil, s.Groups()) - assert.Equal(t, LinkableFields{}, s.LinkableFields()) -} +var ( + testSchemaID = id.MustPropertySchemaID("xx~1.0.0/aa") + testSchema1 = NewSchema().ID(testSchemaID).Groups([]*SchemaGroup{testSchemaGroup1, testSchemaGroup2}).MustBuild() +) func TestSchema_Field(t *testing.T) { - sid := id.MustPropertySchemaID("xx~1.0.0/aa") - sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() - sg := NewSchemaGroup().ID("aaa").Schema(sid).Fields([]*SchemaField{sf}).MustBuild() + tests := []struct { + name string + target *Schema + input id.PropertySchemaFieldID + want *SchemaField + }{ + { + name: "nil schema", + }, + { + name: "found", + target: testSchema1, + input: testSchemaField1.ID(), + want: testSchemaField1, + }, + { + name: "not found", + target: testSchema1, + input: id.PropertySchemaFieldID("zz"), + }, + } - testCases := []struct { - Name string - S *Schema - PTR *Pointer - Input id.PropertySchemaFieldID - Expected *SchemaField + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.Field(tt.input)) + }) + } +} + +func TestSchema_FieldByPointer(t *testing.T) { + tests := []struct { + name string + target *Schema + input *Pointer + want *SchemaField }{ { - Name: "nil schema", + name: "nil schema", }, { - Name: "found", - S: NewSchema().ID(sid).Groups([]*SchemaGroup{sg}).MustBuild(), - PTR: NewPointer(nil, nil, sf.ID().Ref()), - Input: sf.ID(), - Expected: sf, + name: "found", + target: testSchema1, + input: NewPointer(nil, nil, testSchemaField1.ID().Ref()), + want: testSchemaField1, }, { - Name: "not found", - S: NewSchema().ID(sid).Groups([]*SchemaGroup{sg}).MustBuild(), - PTR: NewPointer(nil, nil, id.PropertySchemaFieldID("zz").Ref()), - Input: id.PropertySchemaFieldID("zz"), + name: "not found", + target: testSchema1, + input: NewPointer(nil, nil, id.PropertySchemaFieldID("zz").Ref()), }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - assert.Equal(tt, tc.Expected, tc.S.Field(tc.Input)) - assert.Equal(tt, tc.Expected, tc.S.FieldByPointer(tc.PTR)) + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.FieldByPointer(tt.input)) }) } } func TestSchema_Group(t *testing.T) { - sid := id.MustPropertySchemaID("xx~1.0.0/aa") - sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() - sg := NewSchemaGroup().ID("aaa").Schema(sid).Fields([]*SchemaField{sf}).MustBuild() + tests := []struct { + name string + target *Schema + input SchemaGroupID + want *SchemaGroup + }{ + { + name: "nil schema", + target: nil, + input: testSchemaGroup1.ID(), + want: nil, + }, + { + name: "found", + target: testSchema1, + input: testSchemaGroup1.ID(), + want: testSchemaGroup1, + }, + { + name: "not found", + target: testSchema1, + input: SchemaGroupID("zz"), + want: nil, + }, + } - testCases := []struct { - Name string - S *Schema - PTR *Pointer - Input id.PropertySchemaGroupID - InputField id.PropertySchemaFieldID - Expected *SchemaGroup + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.Group(tt.input)) + }) + } +} + +func TestSchema_GroupByField(t *testing.T) { + tests := []struct { + name string + target *Schema + input FieldID + want *SchemaGroup }{ { - Name: "nil schema", + name: "nil schema", + target: nil, + input: testSchemaField1.ID(), + want: nil, }, { - Name: "found", - S: NewSchema().ID(sid).Groups([]*SchemaGroup{sg}).MustBuild(), - PTR: NewPointer(sg.IDRef(), nil, sf.ID().Ref()), - InputField: sf.ID(), - Input: sg.ID(), - Expected: sg, + name: "found", + target: testSchema1, + input: testSchemaField1.ID(), + want: testSchemaGroup1, }, { - Name: "not found", - S: NewSchema().ID(sid).Groups([]*SchemaGroup{sg}).MustBuild(), - PTR: NewPointer(nil, nil, id.PropertySchemaFieldID("zz").Ref()), - Input: id.PropertySchemaGroupID("zz"), + name: "not found", + target: testSchema1, + input: FieldID("zz"), + want: nil, }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - assert.Equal(tt, tc.Expected, tc.S.Group(tc.Input)) - assert.Equal(tt, tc.Expected, tc.S.GroupByPointer(tc.PTR)) - assert.Equal(tt, tc.Expected, tc.S.GroupByField(tc.InputField)) + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.GroupByField(tt.input)) }) } } -func TestSchema_DetectDuplicatedFields(t *testing.T) { +func TestSchema_GroupAndFields(t *testing.T) { + tests := []struct { + name string + target *Schema + want []SchemaGroupAndField + }{ + { + name: "ok", + target: testSchema1, + want: []SchemaGroupAndField{ + {Group: testSchemaGroup1, Field: testSchemaField1}, + {Group: testSchemaGroup1, Field: testSchemaField2}, + {Group: testSchemaGroup2, Field: testSchemaField3}, + }, + }, + { + name: "empty", + target: &Schema{}, + want: []SchemaGroupAndField{}, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + res := tt.target.GroupAndFields() + assert.Equal(t, tt.want, res) + if len(tt.want) > 0 { + for i, gf := range res { + assert.Same(t, tt.want[i].Group, gf.Group) + assert.Same(t, tt.want[i].Field, gf.Field) + } + } + }) + } +} + +func TestSchema_GroupAndField(t *testing.T) { + type args struct { + f FieldID + } + tests := []struct { + name string + args args + target *Schema + want *SchemaGroupAndField + }{ + { + name: "ok1", + target: testSchema1, + args: args{f: testSchemaField1.ID()}, + want: &SchemaGroupAndField{Group: testSchemaGroup1, Field: testSchemaField1}, + }, + { + name: "ok2", + target: testSchema1, + args: args{f: testSchemaField2.ID()}, + want: &SchemaGroupAndField{Group: testSchemaGroup1, Field: testSchemaField2}, + }, + { + name: "ok3", + target: testSchema1, + args: args{f: testSchemaField3.ID()}, + want: &SchemaGroupAndField{Group: testSchemaGroup2, Field: testSchemaField3}, + }, + { + name: "not found", + target: testSchema1, + args: args{f: "ddd"}, + want: nil, + }, + { + name: "empty", + target: &Schema{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + res := tt.target.GroupAndField(tt.args.f) + assert.Equal(t, tt.want, res) + if tt.want != nil { + assert.Same(t, tt.want.Group, res.Group) + assert.Same(t, tt.want.Field, res.Field) + } + }) + } +} + +func TestLinkableField_Validate(t *testing.T) { sid := id.MustPropertySchemaID("xx~1.0.0/aa") sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() sg := NewSchemaGroup().ID("aaa").Schema(sid).Fields([]*SchemaField{sf}).MustBuild() - testCases := []struct { + tests := []struct { Name string S *Schema LF LinkableFields Expected bool }{ { - Name: "nil schema", + Name: "nil schema", + S: nil, + LF: LinkableFields{}, + Expected: false, }, { Name: "invalid: URL", @@ -125,19 +281,51 @@ func TestSchema_DetectDuplicatedFields(t *testing.T) { Expected: false, }, { - Name: "success", + Name: "empty", S: NewSchema().ID(sid).Groups([]*SchemaGroup{sg}).MustBuild(), LF: LinkableFields{}, Expected: true, }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - res := tc.LF.Validate(tc.S) - assert.Equal(tt, tc.Expected, res) + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + res := tt.LF.Validate(tt.S) + assert.Equal(t, tt.Expected, res) + }) + } +} + +func TestSchemaGroupAndField_IsEmpty(t *testing.T) { + tests := []struct { + name string + target SchemaGroupAndField + want bool + }{ + { + name: "present", + target: SchemaGroupAndField{ + Group: testSchemaGroup1, + Field: testSchemaField1, + }, + want: false, + }, + { + name: "empty", + target: SchemaGroupAndField{}, + want: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gf := SchemaGroupAndField{ + Group: tt.target.Group, + Field: tt.target.Field, + } + assert.Equal(t, tt.want, gf.IsEmpty()) }) } } From 708ab9d9aab74ca48f59cb23d3e8ef610653f4f6 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 7 Dec 2021 15:54:33 +0900 Subject: [PATCH 11/55] fix test --- pkg/dataset/value_optional_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/dataset/value_optional_test.go b/pkg/dataset/value_optional_test.go index 82f82660..b96decc0 100644 --- a/pkg/dataset/value_optional_test.go +++ b/pkg/dataset/value_optional_test.go @@ -328,7 +328,7 @@ func TestOptionalValue_Cast(t *testing.T) { name: "failed to cast", target: &OptionalValue{ov: *value.OptionalFrom(value.TypeLatLng.ValueFrom(LatLng{Lat: 1, Lng: 2}, nil))}, args: args{t: ValueTypeString}, - want: nil, + want: &OptionalValue{ov: *value.NewOptional(value.TypeString, nil)}, }, { name: "empty", From 4f53aeab8c8baf9f45f63d260fa4db70e99b4306 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 7 Dec 2021 15:58:26 +0900 Subject: [PATCH 12/55] add property.SchemaGroupList --- .../adapter/gql/gqlmodel/convert_property.go | 6 +- .../mongo/mongodoc/property_schema.go | 38 +-- internal/usecase/interactor/property.go | 2 +- pkg/plugin/manifest/convert.go | 23 +- pkg/plugin/manifest/convert_test.go | 29 +- pkg/plugin/manifest/parser_translation.go | 2 +- .../manifest/parser_translation_test.go | 6 +- pkg/property/field.go | 2 +- pkg/property/group.go | 4 +- pkg/property/group_list.go | 4 +- pkg/property/property.go | 42 ++- pkg/property/schema.go | 166 +++------- pkg/property/schema_builder.go | 23 +- pkg/property/schema_builder_test.go | 16 +- pkg/property/schema_group.go | 1 - pkg/property/schema_group_list.go | 134 ++++++++ pkg/property/schema_group_list_test.go | 290 +++++++++++++++++ pkg/property/schema_group_test.go | 2 - pkg/property/schema_test.go | 291 +----------------- 19 files changed, 563 insertions(+), 518 deletions(-) create mode 100644 pkg/property/schema_group_list.go create mode 100644 pkg/property/schema_group_list_test.go diff --git a/internal/adapter/gql/gqlmodel/convert_property.go b/internal/adapter/gql/gqlmodel/convert_property.go index 8723d97c..70e800e7 100644 --- a/internal/adapter/gql/gqlmodel/convert_property.go +++ b/internal/adapter/gql/gqlmodel/convert_property.go @@ -209,7 +209,7 @@ func ToPropertySchema(propertySchema *property.Schema) *PropertySchema { return nil } - pgroups := propertySchema.Groups() + pgroups := propertySchema.Groups().Groups() groups := make([]*PropertySchemaGroup, 0, len(pgroups)) for _, g := range pgroups { groups = append(groups, ToPropertySchemaGroup(g)) @@ -225,8 +225,8 @@ func ToPropertySchema(propertySchema *property.Schema) *PropertySchema { func ToPropertyLinkableFields(sid id.PropertySchemaID, l property.LinkableFields) *PropertyLinkableFields { return &PropertyLinkableFields{ SchemaID: sid, - Latlng: l.LatLng.FieldRef(), - URL: l.URL.FieldRef(), + Latlng: l.FieldByType(property.ValueTypeLatLng), + URL: l.FieldByType(property.ValueTypeURL), } } diff --git a/internal/infrastructure/mongo/mongodoc/property_schema.go b/internal/infrastructure/mongo/mongodoc/property_schema.go index 3003d380..60115fbe 100644 --- a/internal/infrastructure/mongo/mongodoc/property_schema.go +++ b/internal/infrastructure/mongo/mongodoc/property_schema.go @@ -34,14 +34,13 @@ type PropertySchemaFieldChoiceDocument struct { } type PropertyLinkableFieldsDocument struct { - LatLng *PropertyPointerDocument - URL *PropertyPointerDocument + LatLng *PropertySchemaFieldPointerDocument + URL *PropertySchemaFieldPointerDocument } -type PropertyPointerDocument struct { - SchemaGroupID *string - ItemID *string - FieldID *string +type PropertySchemaFieldPointerDocument struct { + SchemaGroupID string + FieldID string } type PropertyConditonDocument struct { @@ -113,7 +112,7 @@ func NewPropertySchema(m *property.Schema) (*PropertySchemaDocument, string) { return nil, "" } - pgroups := m.Groups() + pgroups := m.Groups().Groups() groups := make([]*PropertySchemaGroupDocument, 0, len(pgroups)) for _, f := range pgroups { groups = append(groups, newPropertySchemaGroup(f)) @@ -284,30 +283,27 @@ func toModelPropertyLinkableFields(l *PropertyLinkableFieldsDocument) property.L return property.LinkableFields{} } return property.LinkableFields{ - LatLng: toModelPropertyPointer(l.LatLng), - URL: toModelPropertyPointer(l.URL), + LatLng: toModelPropertySchemaFieldPointer(l.LatLng), + URL: toModelPropertySchemaFieldPointer(l.URL), } } -func toModelPropertyPointer(p *PropertyPointerDocument) *property.Pointer { +func toModelPropertySchemaFieldPointer(p *PropertySchemaFieldPointerDocument) *property.SchemaFieldPointer { if p == nil { return nil } - return property.NewPointer( - id.PropertySchemaGroupIDFrom(p.SchemaGroupID), - id.PropertyItemIDFromRef(p.ItemID), - id.PropertySchemaFieldIDFrom(p.FieldID), - ) + return &property.SchemaFieldPointer{ + SchemaGroup: id.PropertySchemaGroupID(p.SchemaGroupID), + Field: id.PropertySchemaFieldID(p.FieldID), + } } -func newDocPropertyPointer(p *property.Pointer) *PropertyPointerDocument { +func newDocPropertyPointer(p *property.SchemaFieldPointer) *PropertySchemaFieldPointerDocument { if p == nil { return nil } - schemaGroupID, itemID, fieldID := p.GetAll() - return &PropertyPointerDocument{ - SchemaGroupID: schemaGroupID.StringRef(), - ItemID: itemID.StringRef(), - FieldID: fieldID.StringRef(), + return &PropertySchemaFieldPointerDocument{ + SchemaGroupID: p.SchemaGroup.String(), + FieldID: p.Field.String(), } } diff --git a/internal/usecase/interactor/property.go b/internal/usecase/interactor/property.go index 5b9f1ea5..91197fdb 100644 --- a/internal/usecase/interactor/property.go +++ b/internal/usecase/interactor/property.go @@ -243,7 +243,7 @@ func (i *Property) UploadFile(ctx context.Context, inp interfaces.UploadFilePara if v == nil { return nil, nil, nil, nil, interfaces.ErrInvalidPropertyValue } - if err = field.Update(v, ps.Field(field.Field())); err != nil { + if err = field.Update(v, ps.Groups().Field(field.Field())); err != nil { return nil, nil, nil, nil, err } diff --git a/pkg/plugin/manifest/convert.go b/pkg/plugin/manifest/convert.go index 4e9c5421..2fdeedcc 100644 --- a/pkg/plugin/manifest/convert.go +++ b/pkg/plugin/manifest/convert.go @@ -197,21 +197,25 @@ func (i *PropertySchema) schema(pluginID id.PluginID, idstr string) (*property.S Build() } - // items - items := make([]*property.SchemaGroup, 0, len(i.Groups)) + // groups + groups := make([]*property.SchemaGroup, 0, len(i.Groups)) for _, d := range i.Groups { item, err := d.schemaGroup(psid) if err != nil { return nil, rerror.From(fmt.Sprintf("item (%s)", d.ID), err) } - items = append(items, item) + groups = append(groups, item) + } + sgroups := property.NewSchemaGroupList(groups) + if sgroups == nil { + return nil, fmt.Errorf("invalid group; it is empty or it may contain some duplicated groups or fields") } // schema schema, err := property.NewSchema(). ID(psid). Version(int(i.Version)). - Groups(items). + GroupList(sgroups). LinkableFields(i.Linkable.linkable()). Build() if err != nil { @@ -230,15 +234,14 @@ func (p *PropertyLinkableFields) linkable() property.LinkableFields { } } -func (p *PropertyPointer) pointer() *property.Pointer { +func (p *PropertyPointer) pointer() *property.SchemaFieldPointer { if p == nil || p.FieldID == "" && p.SchemaGroupID == "" { return nil } - return property.NewPointer( - id.PropertySchemaGroupIDFrom(&p.SchemaGroupID), - nil, - id.PropertySchemaFieldIDFrom(&p.FieldID), - ) + return &property.SchemaFieldPointer{ + SchemaGroup: id.PropertySchemaGroupID(p.SchemaGroupID), + Field: id.PropertySchemaFieldID(p.FieldID), + } } func (i PropertySchemaGroup) schemaGroup(sid id.PropertySchemaID) (*property.SchemaGroup, error) { diff --git a/pkg/plugin/manifest/convert_test.go b/pkg/plugin/manifest/convert_test.go index 73d04540..b0bc8fa4 100644 --- a/pkg/plugin/manifest/convert_test.go +++ b/pkg/plugin/manifest/convert_test.go @@ -329,12 +329,10 @@ func TestExtension(t *testing.T) { } func TestPointer(t *testing.T) { - sg := "aaa" - f := "xxx" testCases := []struct { name string pp *PropertyPointer - expected *property.Pointer + expected *property.SchemaFieldPointer }{ { name: "failed nil PropertyPointer", @@ -352,10 +350,13 @@ func TestPointer(t *testing.T) { { name: "success", pp: &PropertyPointer{ - FieldID: "xxx", SchemaGroupID: "aaa", + FieldID: "xxx", + }, + expected: &property.SchemaFieldPointer{ + SchemaGroup: id.PropertySchemaGroupID("aaa"), + Field: id.PropertySchemaFieldID("xxx"), }, - expected: property.NewPointer(id.PropertySchemaGroupIDFrom(&sg), nil, id.PropertySchemaFieldIDFrom(&f)), }, } for _, tc := range testCases { @@ -366,6 +367,7 @@ func TestPointer(t *testing.T) { }) } } + func TestCondition(t *testing.T) { v := toValue("xxx", "string") testCases := []struct { @@ -402,7 +404,6 @@ func TestCondition(t *testing.T) { func TestLinkable(t *testing.T) { l := "location" - d := "default" u := "url" testCases := []struct { name string @@ -427,8 +428,14 @@ func TestLinkable(t *testing.T) { }, }, expected: property.LinkableFields{ - LatLng: property.NewPointer(id.PropertySchemaGroupIDFrom(&d), nil, id.PropertySchemaFieldIDFrom(&l)), - URL: property.NewPointer(id.PropertySchemaGroupIDFrom(&d), nil, id.PropertySchemaFieldIDFrom(&u)), + LatLng: &property.SchemaFieldPointer{ + SchemaGroup: id.PropertySchemaGroupID("default"), + Field: id.PropertySchemaFieldID(l), + }, + URL: &property.SchemaFieldPointer{ + SchemaGroup: id.PropertySchemaGroupID("default"), + Field: id.PropertySchemaFieldID(u), + }, }, }, } @@ -507,11 +514,11 @@ func TestSchema(t *testing.T) { tt.Parallel() res, err := tc.ps.schema(tc.pid, tc.psid) if tc.err == "" { - assert.Equal(tt, len(tc.expected.Groups()), len(res.Groups())) + assert.Equal(tt, len(tc.expected.Groups().Groups()), len(res.Groups().Groups())) assert.Equal(tt, tc.expected.LinkableFields(), res.LinkableFields()) assert.Equal(tt, tc.expected.Version(), res.Version()) - if len(res.Groups()) > 0 { - exg := tc.expected.Group(res.Groups()[0].ID()) + if len(res.Groups().Groups()) > 0 { + exg := tc.expected.Groups().Group(res.Groups().Groups()[0].ID()) assert.NotNil(tt, exg) } } else { diff --git a/pkg/plugin/manifest/parser_translation.go b/pkg/plugin/manifest/parser_translation.go index 54dd00fa..974b67e6 100644 --- a/pkg/plugin/manifest/parser_translation.go +++ b/pkg/plugin/manifest/parser_translation.go @@ -92,7 +92,7 @@ func MergeManifestTranslation(m *Manifest, tl map[string]*TranslationRoot) *Mani } for key, tsg := range te.PropertySchema { - psg := ps.Group(id.PropertySchemaGroupID(key)) + psg := ps.Groups().Group(id.PropertySchemaGroupID(key)) if psg == nil { continue } diff --git a/pkg/plugin/manifest/parser_translation_test.go b/pkg/plugin/manifest/parser_translation_test.go index 1dd0b156..8d10fded 100644 --- a/pkg/plugin/manifest/parser_translation_test.go +++ b/pkg/plugin/manifest/parser_translation_test.go @@ -192,9 +192,9 @@ func TestMergeManifestTranslation(t *testing.T) { assert.Equal(tt, tc.Expected.PluginName, res.Plugin.Name()) assert.Equal(tt, tc.Expected.PluginDesc, res.Plugin.Description()) assert.Equal(tt, tc.Expected.ExtName, res.Plugin.Extension(id.PluginExtensionID("test_ext")).Name()) - assert.Equal(tt, tc.Expected.PsTitle, res.ExtensionSchema[0].Group("test_ps").Title()) - assert.Equal(tt, tc.Expected.FieldTitle, res.ExtensionSchema[0].Group("test_ps").Field("test_field").Title()) - assert.Equal(tt, tc.Expected.FieldDesc, res.ExtensionSchema[0].Group("test_ps").Field("test_field").Description()) + assert.Equal(tt, tc.Expected.PsTitle, res.ExtensionSchema[0].Groups().Group("test_ps").Title()) + assert.Equal(tt, tc.Expected.FieldTitle, res.ExtensionSchema[0].Groups().Group("test_ps").Field("test_field").Title()) + assert.Equal(tt, tc.Expected.FieldDesc, res.ExtensionSchema[0].Groups().Group("test_ps").Field("test_field").Description()) }) } } diff --git a/pkg/property/field.go b/pkg/property/field.go index 3ac05346..cc94b623 100644 --- a/pkg/property/field.go +++ b/pkg/property/field.go @@ -145,7 +145,7 @@ func (p *Field) MigrateSchema(ctx context.Context, newSchema *Schema, dl dataset } fid := p.Field() - schemaField := newSchema.Field(fid) + schemaField := newSchema.Groups().Field(fid) // If field is not found in new schema, this field should be removed invalid := schemaField == nil diff --git a/pkg/property/group.go b/pkg/property/group.go index 727138ef..d0a7c5bb 100644 --- a/pkg/property/group.go +++ b/pkg/property/group.go @@ -152,7 +152,7 @@ func (g *Group) GetOrCreateField(ps *Schema, fid id.PropertySchemaFieldID) (*Fie if g == nil || ps == nil || !g.Schema().Equal(ps.ID()) { return nil, false } - psg := ps.Group(g.SchemaGroup()) + psg := ps.Groups().Group(g.SchemaGroup()) if psg == nil { return nil, false } @@ -226,7 +226,7 @@ func (g *Group) UpdateNameFieldValue(ps *Schema, value *Value) error { if g == nil || ps == nil || !g.Schema().Equal(ps.ID()) { return nil } - if psg := ps.GroupByPointer(NewPointer(&g.itemBase.SchemaGroup, nil, nil)); psg != nil { + if psg := ps.Groups().Group(g.itemBase.SchemaGroup); psg != nil { if representativeField := psg.RepresentativeFieldID(); representativeField != nil { if f, _ := g.GetOrCreateField(ps, *representativeField); f != nil { return f.Update(value, psg.Field(*representativeField)) diff --git a/pkg/property/group_list.go b/pkg/property/group_list.go index 22f06c76..a05e514e 100644 --- a/pkg/property/group_list.go +++ b/pkg/property/group_list.go @@ -291,7 +291,7 @@ func (g *GroupList) GetOrCreateField(ps *Schema, ptr *Pointer) (*Field, bool) { if g == nil || ptr == nil || ps == nil || ps.ID() != g.Schema() { return nil, false } - psg := ps.Group(g.SchemaGroup()) + psg := ps.Groups().Group(g.SchemaGroup()) if psg == nil { return nil, false } @@ -313,7 +313,7 @@ func (g *GroupList) CreateAndAddListItem(ps *Schema, index *int) *Group { if g == nil || ps == nil || !g.Schema().Equal(ps.ID()) { return nil } - psg := ps.Group(g.SchemaGroup()) + psg := ps.Groups().Group(g.SchemaGroup()) if psg == nil { return nil } diff --git a/pkg/property/property.go b/pkg/property/property.go index 497dda2a..03ebd7a7 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -247,7 +247,7 @@ func (p *Property) UpdateValue(ps *Schema, ptr *Pointer, v *Value) (*Field, *Gro return nil, nil, nil, nil } - if err := field.Update(v, ps.Field(field.Field())); err != nil { + if err := field.Update(v, ps.Groups().Field(field.Field())); err != nil { return nil, nil, nil, err } @@ -302,7 +302,7 @@ func (p *Property) GetOrCreateItem(ps *Schema, ptr *Pointer) (Item, *GroupList) return nil, nil } - psg := ps.Group(psgid) + psg := ps.Groups().Group(psgid) if psg == nil { return nil, nil } @@ -326,9 +326,9 @@ func (p *Property) GetOrCreateGroup(ps *Schema, ptr *Pointer) (*Group, *GroupLis var psg *SchemaGroup if psgid, ok := ptr.ItemBySchemaGroup(); ok { - psg = ps.Group(psgid) + psg = ps.Groups().Group(psgid) } else if f, ok := ptr.Field(); ok { - psg = ps.GroupByField(f) + psg = ps.Groups().GroupByField(f) } if psg == nil { return nil, nil @@ -345,9 +345,9 @@ func (p *Property) GetOrCreateGroupList(ps *Schema, ptr *Pointer) *GroupList { var psg *SchemaGroup if psgid, ok := ptr.ItemBySchemaGroup(); ok { - psg = ps.Group(psgid) + psg = ps.Groups().Group(psgid) } else if f, ok := ptr.Field(); ok { - psg = ps.GroupByField(f) + psg = ps.Groups().GroupByField(f) } if psg == nil { return nil @@ -398,22 +398,19 @@ func (p *Property) UpdateLinkableValue(s *Schema, v *Value) { return } - var ptr *Pointer - switch v.Type() { - case ValueTypeLatLng: - ptr = s.linkable.LatLng - case ValueTypeURL: - ptr = s.linkable.URL + sfid := s.linkable.FieldByType(v.Type()) + if sfid == nil { + return } - sf := s.FieldByPointer(ptr) + sf := s.Groups().GroupAndField(*sfid) if sf == nil { return } - f, _, _, ok := p.GetOrCreateField(s, ptr) + f, _, _, ok := p.GetOrCreateField(s, sf.Pointer()) if ok { - if err := f.Update(v, sf); err != nil { + if err := f.Update(v, sf.Field); err != nil { p.Prune() } } @@ -424,20 +421,17 @@ func (p *Property) AutoLinkField(s *Schema, v ValueType, d id.DatasetSchemaID, d return } - var ptr *Pointer - switch v { - case ValueTypeLatLng: - ptr = s.linkable.LatLng - case ValueTypeURL: - ptr = s.linkable.URL + sfid := s.linkable.FieldByType(v) + if sfid == nil { + return } - sf := s.FieldByPointer(ptr) + sf := s.Groups().GroupAndField(*sfid) if sf == nil { return } - f, _, _, ok := p.GetOrCreateField(s, ptr) + f, _, _, ok := p.GetOrCreateField(s, sf.Pointer()) if ok { if ds == nil { f.Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAtField(d, *df)})) @@ -474,7 +468,7 @@ func (p *Property) ValidateSchema(ps *Schema) error { for _, i := range p.items { sg := i.SchemaGroup() - if err := i.ValidateSchema(ps.Group(sg)); err != nil { + if err := i.ValidateSchema(ps.Groups().Group(sg)); err != nil { return fmt.Errorf("%s (%s): %w", p.ID(), sg, err) } } diff --git a/pkg/property/schema.go b/pkg/property/schema.go index 71e14ac9..3ed3afc8 100644 --- a/pkg/property/schema.go +++ b/pkg/property/schema.go @@ -5,18 +5,18 @@ import "github.com/reearth/reearth-backend/pkg/id" type Schema struct { id id.PropertySchemaID version int - groups []*SchemaGroup + groups *SchemaGroupList linkable LinkableFields } -type SchemaGroupAndField struct { - Group *SchemaGroup - Field *SchemaField +type SchemaFieldPointer struct { + SchemaGroup SchemaGroupID + Field FieldID } type LinkableFields struct { - LatLng *Pointer - URL *Pointer + LatLng *SchemaFieldPointer + URL *SchemaFieldPointer } func (p *Schema) ID() id.PropertySchemaID { @@ -34,131 +34,11 @@ func (p *Schema) Version() int { return p.version } -func (p *Schema) Fields() []*SchemaField { +func (p *Schema) Groups() *SchemaGroupList { if p == nil { return nil } - fields := []*SchemaField{} - for _, g := range p.groups { - fields = append(fields, g.Fields()...) - } - return fields -} - -func (p *Schema) Field(id id.PropertySchemaFieldID) *SchemaField { - if p == nil { - return nil - } - for _, g := range p.groups { - if f := g.Field(id); f != nil { - return f - } - } - return nil -} - -func (p *Schema) FieldByPointer(ptr *Pointer) *SchemaField { - if p == nil { - return nil - } - g := p.GroupByPointer(ptr) - if g == nil { - return nil - } - return g.FieldByPointer(ptr) -} - -func (p *Schema) Groups() []*SchemaGroup { - if p == nil { - return nil - } - return append([]*SchemaGroup{}, p.groups...) -} - -func (p *Schema) Group(id id.PropertySchemaGroupID) *SchemaGroup { - if p == nil { - return nil - } - for _, f := range p.groups { - if f.ID() == id { - return f - } - } - return nil -} - -func (p *Schema) GroupByField(id id.PropertySchemaFieldID) *SchemaGroup { - if p == nil { - return nil - } - for _, f := range p.groups { - if f.HasField(id) { - return f - } - } - return nil -} - -func (p *Schema) GroupByPointer(ptr *Pointer) *SchemaGroup { - if p == nil { - return nil - } - - if gid, ok := ptr.ItemBySchemaGroup(); ok { - return p.Group(gid) - } - if fid, ok := ptr.Field(); ok { - for _, g := range p.groups { - if g.HasField(fid) { - return g - } - } - } - - return nil -} - -func (gf SchemaGroupAndField) IsEmpty() bool { - return gf.Group == nil && gf.Field == nil -} - -func (p *Schema) GroupAndFields() []SchemaGroupAndField { - if p == nil { - return nil - } - fields := []SchemaGroupAndField{} - for _, g := range p.groups { - for _, f := range g.Fields() { - fields = append(fields, SchemaGroupAndField{Group: g, Field: f}) - } - } - return fields -} - -func (p *Schema) GroupAndField(f FieldID) *SchemaGroupAndField { - if p == nil { - return nil - } - for _, g := range p.groups { - if gf := g.Field(f); gf != nil { - return &SchemaGroupAndField{Group: g, Field: gf} - } - } - return nil -} - -func (s *Schema) DetectDuplicatedFields() []id.PropertySchemaFieldID { - duplicated := []id.PropertySchemaFieldID{} - ids := map[id.PropertySchemaFieldID]struct{}{} - for _, f := range s.Fields() { - i := f.ID() - if _, ok := ids[i]; ok { - duplicated = append(duplicated, i) - return duplicated - } - ids[i] = struct{}{} - } - return nil + return p.groups } func (p *Schema) LinkableFields() LinkableFields { @@ -180,14 +60,40 @@ func (l LinkableFields) Validate(s *Schema) bool { return false } if l.LatLng != nil { - if f := s.FieldByPointer(l.LatLng); f == nil { + if f := s.groups.Field(l.LatLng.Field); f == nil { return false } } if l.URL != nil { - if f := s.FieldByPointer(l.URL); f == nil { + if f := s.groups.Field(l.URL.Field); f == nil { return false } } return true } + +func (l LinkableFields) PointerByType(ty ValueType) *SchemaFieldPointer { + switch ty { + case ValueTypeLatLng: + return l.LatLng + case ValueTypeURL: + return l.URL + } + return nil +} + +func (l LinkableFields) FieldByType(ty ValueType) *FieldID { + p := l.PointerByType(ty) + if p == nil { + return nil + } + return p.Field.Ref() +} + +func (p *SchemaFieldPointer) Clone() *SchemaFieldPointer { + if p == nil { + return p + } + p2 := *p + return &p2 +} diff --git a/pkg/property/schema_builder.go b/pkg/property/schema_builder.go index d62a30fb..8429b6d4 100644 --- a/pkg/property/schema_builder.go +++ b/pkg/property/schema_builder.go @@ -2,7 +2,6 @@ package property import ( "errors" - "fmt" "github.com/reearth/reearth-backend/pkg/id" ) @@ -28,9 +27,6 @@ func (b *SchemaBuilder) Build() (*Schema, error) { if b.p.id.IsNil() { return nil, id.ErrInvalidID } - if d := b.p.DetectDuplicatedFields(); len(d) > 0 { - return nil, fmt.Errorf("%s: %s %s", ErrDuplicatedField, b.p.id, d) - } if !b.p.linkable.Validate(b.p) { return nil, ErrInvalidPropertyLinkableField } @@ -56,19 +52,12 @@ func (b *SchemaBuilder) Version(version int) *SchemaBuilder { } func (b *SchemaBuilder) Groups(groups []*SchemaGroup) *SchemaBuilder { - newGroups := []*SchemaGroup{} - ids := map[id.PropertySchemaGroupID]struct{}{} - for _, f := range groups { - if f == nil { - continue - } - if _, ok := ids[f.ID()]; ok { - continue - } - ids[f.ID()] = struct{}{} - newGroups = append(newGroups, f) - } - b.p.groups = newGroups + b.p.groups = NewSchemaGroupList(groups) + return b +} + +func (b *SchemaBuilder) GroupList(groups *SchemaGroupList) *SchemaBuilder { + b.p.groups = groups return b } diff --git a/pkg/property/schema_builder_test.go b/pkg/property/schema_builder_test.go index 9d7dfbbe..4f124f85 100644 --- a/pkg/property/schema_builder_test.go +++ b/pkg/property/schema_builder_test.go @@ -2,7 +2,6 @@ package property import ( "errors" - "fmt" "testing" "github.com/reearth/reearth-backend/pkg/id" @@ -12,7 +11,6 @@ import ( func TestSchemaBuilder_Build(t *testing.T) { sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() sg := NewSchemaGroup().ID("aaa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() - sg2 := NewSchemaGroup().ID("daa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() testCases := []struct { Name string Id id.PropertySchemaID @@ -34,15 +32,9 @@ func TestSchemaBuilder_Build(t *testing.T) { { Name: "fail: invalid linkable field", Id: id.MustPropertySchemaID("xx~1.0.0/aa"), - Linkable: LinkableFields{LatLng: NewPointer(nil, nil, id.PropertySchemaFieldID("xx").Ref())}, + Linkable: LinkableFields{LatLng: &SchemaFieldPointer{Field: FieldID("xx")}}, Err: ErrInvalidPropertyLinkableField, }, - { - Name: "fail: duplicated field", - Id: id.MustPropertySchemaID("xx~1.0.0/aa"), - Groups: []*SchemaGroup{sg, sg2}, - Err: fmt.Errorf("%s: %s %s", ErrDuplicatedField, id.MustPropertySchemaID("xx~1.0.0/aa"), []id.PropertySchemaFieldID{"aa"}), - }, { Name: "success", Id: id.MustPropertySchemaID("xx~1.0.0/aa"), @@ -69,7 +61,7 @@ func TestSchemaBuilder_Build(t *testing.T) { Build() if err == nil { assert.Equal(tt, tc.Expected.Linkable, res.LinkableFields()) - assert.Equal(tt, tc.Expected.Groups, res.Groups()) + assert.Equal(tt, tc.Expected.Groups, res.Groups().Groups()) assert.Equal(tt, tc.Expected.Id, res.ID()) assert.Equal(tt, tc.Expected.Version, res.Version()) } else { @@ -104,7 +96,7 @@ func TestSchemaBuilder_MustBuild(t *testing.T) { { Name: "fail: invalid linkable field", Id: id.MustPropertySchemaID("xx~1.0.0/aa"), - Linkable: LinkableFields{LatLng: NewPointer(nil, nil, id.PropertySchemaFieldID("xx").Ref())}, + Linkable: LinkableFields{LatLng: &SchemaFieldPointer{Field: FieldID("xx")}}, Fails: true, }, { @@ -152,7 +144,7 @@ func TestSchemaBuilder_MustBuild(t *testing.T) { LinkableFields(tc.Linkable). MustBuild() assert.Equal(tt, tc.Expected.Linkable, res.LinkableFields()) - assert.Equal(tt, tc.Expected.Groups, res.Groups()) + assert.Equal(tt, tc.Expected.Groups, res.Groups().Groups()) assert.Equal(tt, tc.Expected.Id, res.ID()) assert.Equal(tt, tc.Expected.Version, res.Version()) } diff --git a/pkg/property/schema_group.go b/pkg/property/schema_group.go index 73c0955f..0b95acf5 100644 --- a/pkg/property/schema_group.go +++ b/pkg/property/schema_group.go @@ -16,7 +16,6 @@ type SchemaGroup struct { representativeField *id.PropertySchemaFieldID } -// ID returns id func (s *SchemaGroup) ID() id.PropertySchemaGroupID { if s == nil { return id.PropertySchemaGroupID("") diff --git a/pkg/property/schema_group_list.go b/pkg/property/schema_group_list.go new file mode 100644 index 00000000..22a76a52 --- /dev/null +++ b/pkg/property/schema_group_list.go @@ -0,0 +1,134 @@ +package property + +import "github.com/reearth/reearth-backend/pkg/id" + +type SchemaGroupList struct { + groups []*SchemaGroup +} + +type SchemaGroupAndField struct { + Group *SchemaGroup + Field *SchemaField +} + +func NewSchemaGroupList(p []*SchemaGroup) *SchemaGroupList { + sgl := &SchemaGroupList{ + groups: append(p[:0:0], p...), + } + if len(sgl.duplicatedGroups()) > 0 { + return nil + } + return sgl +} + +func (p *SchemaGroupList) Groups() []*SchemaGroup { + if p == nil { + return nil + } + return append(p.groups[:0:0], p.groups...) +} + +func (p *SchemaGroupList) Fields() []*SchemaField { + if p == nil { + return nil + } + + fields := []*SchemaField{} + for _, g := range p.groups { + fields = append(fields, g.Fields()...) + } + return fields +} + +func (p *SchemaGroupList) GroupAndFields() []SchemaGroupAndField { + if p == nil { + return nil + } + fields := []SchemaGroupAndField{} + for _, g := range p.groups { + for _, f := range g.Fields() { + fields = append(fields, SchemaGroupAndField{Group: g, Field: f}) + } + } + return fields +} + +func (p *SchemaGroupList) Field(id id.PropertySchemaFieldID) *SchemaField { + if p == nil { + return nil + } + + for _, g := range p.groups { + if f := g.Field(id); f != nil { + return f + } + } + return nil +} + +func (p *SchemaGroupList) Group(id id.PropertySchemaGroupID) *SchemaGroup { + if p == nil { + return nil + } + + for _, f := range p.groups { + if f.ID() == id { + return f + } + } + return nil +} + +func (p *SchemaGroupList) GroupByField(id id.PropertySchemaFieldID) *SchemaGroup { + if p == nil { + return nil + } + + for _, f := range p.groups { + if f.HasField(id) { + return f + } + } + + return nil +} + +func (p *SchemaGroupList) GroupAndField(f FieldID) *SchemaGroupAndField { + if p == nil { + return nil + } + for _, g := range p.groups { + if gf := g.Field(f); gf != nil { + return &SchemaGroupAndField{Group: g, Field: gf} + } + } + return nil +} + +func (s *SchemaGroupList) duplicatedGroups() []SchemaGroupID { + if s == nil { + return nil + } + + var duplicated []SchemaGroupID + ids := map[SchemaGroupID]struct{}{} + for _, f := range s.Groups() { + i := f.ID() + if _, ok := ids[i]; ok { + duplicated = append(duplicated, i) + } + ids[i] = struct{}{} + } + return duplicated +} + +func (gf SchemaGroupAndField) IsEmpty() bool { + return gf.Group == nil && gf.Field == nil +} + +func (gf SchemaGroupAndField) Pointer() *Pointer { + if gf.Group == nil || gf.Field == nil { + return nil + } + return PointFieldBySchemaGroup(gf.Group.ID(), gf.Field.ID()) +} diff --git a/pkg/property/schema_group_list_test.go b/pkg/property/schema_group_list_test.go new file mode 100644 index 00000000..059e855f --- /dev/null +++ b/pkg/property/schema_group_list_test.go @@ -0,0 +1,290 @@ +package property + +import ( + "testing" + + "github.com/reearth/reearth-backend/pkg/id" + "github.com/stretchr/testify/assert" +) + +var ( + testSchemaGroupList1 = NewSchemaGroupList([]*SchemaGroup{testSchemaGroup1, testSchemaGroup2}) +) + +func TestNewSchemaGroupList(t *testing.T) { + type args struct { + p []*SchemaGroup + } + tests := []struct { + name string + args args + want *SchemaGroupList + }{ + { + name: "ok", + args: args{ + p: []*SchemaGroup{testSchemaGroup1, testSchemaGroup2}, + }, + want: &SchemaGroupList{groups: []*SchemaGroup{testSchemaGroup1, testSchemaGroup2}}, + }, + { + name: "duplicated groups", + args: args{ + p: []*SchemaGroup{testSchemaGroup1, testSchemaGroup1}, + }, + want: nil, + }, + { + name: "nil", + args: args{ + p: nil, + }, + want: &SchemaGroupList{groups: nil}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, NewSchemaGroupList(tt.args.p)) + }) + } +} + +func TestSchema_Field(t *testing.T) { + tests := []struct { + name string + target *SchemaGroupList + input id.PropertySchemaFieldID + want *SchemaField + }{ + { + name: "nil schema", + }, + { + name: "found", + target: testSchemaGroupList1, + input: testSchemaField1.ID(), + want: testSchemaField1, + }, + { + name: "not found", + target: testSchemaGroupList1, + input: id.PropertySchemaFieldID("zz"), + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.Field(tt.input)) + }) + } +} + +func TestSchema_Group(t *testing.T) { + tests := []struct { + name string + target *SchemaGroupList + input SchemaGroupID + want *SchemaGroup + }{ + { + name: "nil schema", + target: nil, + input: testSchemaGroup1.ID(), + want: nil, + }, + { + name: "found", + target: testSchemaGroupList1, + input: testSchemaGroup1.ID(), + want: testSchemaGroup1, + }, + { + name: "not found", + target: testSchemaGroupList1, + input: SchemaGroupID("zz"), + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.Group(tt.input)) + }) + } +} + +func TestSchemaGroupList_GroupByField(t *testing.T) { + tests := []struct { + name string + target *SchemaGroupList + input FieldID + want *SchemaGroup + }{ + { + name: "nil schema", + target: nil, + input: testSchemaField1.ID(), + want: nil, + }, + { + name: "found", + target: testSchemaGroupList1, + input: testSchemaField1.ID(), + want: testSchemaGroup1, + }, + { + name: "not found", + target: testSchemaGroupList1, + input: FieldID("zz"), + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.GroupByField(tt.input)) + }) + } +} + +func TestSchemaGroupList_GroupAndFields(t *testing.T) { + tests := []struct { + name string + target *SchemaGroupList + want []SchemaGroupAndField + }{ + { + name: "ok", + target: testSchemaGroupList1, + want: []SchemaGroupAndField{ + {Group: testSchemaGroup1, Field: testSchemaField1}, + {Group: testSchemaGroup1, Field: testSchemaField2}, + {Group: testSchemaGroup2, Field: testSchemaField3}, + }, + }, + { + name: "empty", + target: &SchemaGroupList{}, + want: []SchemaGroupAndField{}, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + res := tt.target.GroupAndFields() + assert.Equal(t, tt.want, res) + if len(tt.want) > 0 { + for i, gf := range res { + assert.Same(t, tt.want[i].Group, gf.Group) + assert.Same(t, tt.want[i].Field, gf.Field) + } + } + }) + } +} + +func TestSchemaGroupList_GroupAndField(t *testing.T) { + type args struct { + f FieldID + } + tests := []struct { + name string + args args + target *SchemaGroupList + want *SchemaGroupAndField + }{ + { + name: "ok1", + target: testSchemaGroupList1, + args: args{f: testSchemaField1.ID()}, + want: &SchemaGroupAndField{Group: testSchemaGroup1, Field: testSchemaField1}, + }, + { + name: "ok2", + target: testSchemaGroupList1, + args: args{f: testSchemaField2.ID()}, + want: &SchemaGroupAndField{Group: testSchemaGroup1, Field: testSchemaField2}, + }, + { + name: "ok3", + target: testSchemaGroupList1, + args: args{f: testSchemaField3.ID()}, + want: &SchemaGroupAndField{Group: testSchemaGroup2, Field: testSchemaField3}, + }, + { + name: "not found", + target: testSchemaGroupList1, + args: args{f: "ddd"}, + want: nil, + }, + { + name: "empty", + target: &SchemaGroupList{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + res := tt.target.GroupAndField(tt.args.f) + assert.Equal(t, tt.want, res) + if tt.want != nil { + assert.Same(t, tt.want.Group, res.Group) + assert.Same(t, tt.want.Field, res.Field) + } + }) + } +} + +func TestSchemaGroupAndField_IsEmpty(t *testing.T) { + tests := []struct { + name string + target SchemaGroupAndField + want bool + }{ + { + name: "present", + target: SchemaGroupAndField{ + Group: testSchemaGroup1, + Field: testSchemaField1, + }, + want: false, + }, + { + name: "empty", + target: SchemaGroupAndField{}, + want: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gf := SchemaGroupAndField{ + Group: tt.target.Group, + Field: tt.target.Field, + } + assert.Equal(t, tt.want, gf.IsEmpty()) + }) + } +} diff --git a/pkg/property/schema_group_test.go b/pkg/property/schema_group_test.go index 0906328c..5347f76b 100644 --- a/pkg/property/schema_group_test.go +++ b/pkg/property/schema_group_test.go @@ -65,8 +65,6 @@ func TestSchemaGroup(t *testing.T) { assert.Equal(tt, tc.Expected.GID, tc.G.ID()) assert.Equal(tt, tc.Expected.GIDRef, tc.G.IDRef()) - assert.Equal(tt, tc.Expected.SID, tc.G.Schema()) - assert.Equal(tt, tc.Expected.SIDRef, tc.G.SchemaRef()) assert.Equal(tt, tc.Expected.Fields, tc.G.Fields()) assert.Equal(tt, tc.Expected.IsList, tc.G.IsList()) assert.Equal(tt, tc.Expected.IsAvailableIf, tc.G.IsAvailableIf()) diff --git a/pkg/property/schema_test.go b/pkg/property/schema_test.go index 5cd3b51c..7c055dd5 100644 --- a/pkg/property/schema_test.go +++ b/pkg/property/schema_test.go @@ -12,245 +12,6 @@ var ( testSchema1 = NewSchema().ID(testSchemaID).Groups([]*SchemaGroup{testSchemaGroup1, testSchemaGroup2}).MustBuild() ) -func TestSchema_Field(t *testing.T) { - tests := []struct { - name string - target *Schema - input id.PropertySchemaFieldID - want *SchemaField - }{ - { - name: "nil schema", - }, - { - name: "found", - target: testSchema1, - input: testSchemaField1.ID(), - want: testSchemaField1, - }, - { - name: "not found", - target: testSchema1, - input: id.PropertySchemaFieldID("zz"), - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - assert.Equal(t, tt.want, tt.target.Field(tt.input)) - }) - } -} - -func TestSchema_FieldByPointer(t *testing.T) { - tests := []struct { - name string - target *Schema - input *Pointer - want *SchemaField - }{ - { - name: "nil schema", - }, - { - name: "found", - target: testSchema1, - input: NewPointer(nil, nil, testSchemaField1.ID().Ref()), - want: testSchemaField1, - }, - { - name: "not found", - target: testSchema1, - input: NewPointer(nil, nil, id.PropertySchemaFieldID("zz").Ref()), - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - assert.Equal(t, tt.want, tt.target.FieldByPointer(tt.input)) - }) - } -} - -func TestSchema_Group(t *testing.T) { - tests := []struct { - name string - target *Schema - input SchemaGroupID - want *SchemaGroup - }{ - { - name: "nil schema", - target: nil, - input: testSchemaGroup1.ID(), - want: nil, - }, - { - name: "found", - target: testSchema1, - input: testSchemaGroup1.ID(), - want: testSchemaGroup1, - }, - { - name: "not found", - target: testSchema1, - input: SchemaGroupID("zz"), - want: nil, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - assert.Equal(t, tt.want, tt.target.Group(tt.input)) - }) - } -} - -func TestSchema_GroupByField(t *testing.T) { - tests := []struct { - name string - target *Schema - input FieldID - want *SchemaGroup - }{ - { - name: "nil schema", - target: nil, - input: testSchemaField1.ID(), - want: nil, - }, - { - name: "found", - target: testSchema1, - input: testSchemaField1.ID(), - want: testSchemaGroup1, - }, - { - name: "not found", - target: testSchema1, - input: FieldID("zz"), - want: nil, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - assert.Equal(t, tt.want, tt.target.GroupByField(tt.input)) - }) - } -} - -func TestSchema_GroupAndFields(t *testing.T) { - tests := []struct { - name string - target *Schema - want []SchemaGroupAndField - }{ - { - name: "ok", - target: testSchema1, - want: []SchemaGroupAndField{ - {Group: testSchemaGroup1, Field: testSchemaField1}, - {Group: testSchemaGroup1, Field: testSchemaField2}, - {Group: testSchemaGroup2, Field: testSchemaField3}, - }, - }, - { - name: "empty", - target: &Schema{}, - want: []SchemaGroupAndField{}, - }, - { - name: "nil", - target: nil, - want: nil, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - res := tt.target.GroupAndFields() - assert.Equal(t, tt.want, res) - if len(tt.want) > 0 { - for i, gf := range res { - assert.Same(t, tt.want[i].Group, gf.Group) - assert.Same(t, tt.want[i].Field, gf.Field) - } - } - }) - } -} - -func TestSchema_GroupAndField(t *testing.T) { - type args struct { - f FieldID - } - tests := []struct { - name string - args args - target *Schema - want *SchemaGroupAndField - }{ - { - name: "ok1", - target: testSchema1, - args: args{f: testSchemaField1.ID()}, - want: &SchemaGroupAndField{Group: testSchemaGroup1, Field: testSchemaField1}, - }, - { - name: "ok2", - target: testSchema1, - args: args{f: testSchemaField2.ID()}, - want: &SchemaGroupAndField{Group: testSchemaGroup1, Field: testSchemaField2}, - }, - { - name: "ok3", - target: testSchema1, - args: args{f: testSchemaField3.ID()}, - want: &SchemaGroupAndField{Group: testSchemaGroup2, Field: testSchemaField3}, - }, - { - name: "not found", - target: testSchema1, - args: args{f: "ddd"}, - want: nil, - }, - { - name: "empty", - target: &Schema{}, - want: nil, - }, - { - name: "nil", - target: nil, - want: nil, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - res := tt.target.GroupAndField(tt.args.f) - assert.Equal(t, tt.want, res) - if tt.want != nil { - assert.Same(t, tt.want.Group, res.Group) - assert.Same(t, tt.want.Field, res.Field) - } - }) - } -} - func TestLinkableField_Validate(t *testing.T) { sid := id.MustPropertySchemaID("xx~1.0.0/aa") sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() @@ -269,15 +30,23 @@ func TestLinkableField_Validate(t *testing.T) { Expected: false, }, { - Name: "invalid: URL", - S: NewSchema().ID(sid).Groups([]*SchemaGroup{sg}).MustBuild(), - LF: LinkableFields{URL: NewPointer(nil, nil, id.PropertySchemaFieldID("xx").Ref())}, + Name: "invalid: URL", + S: NewSchema().ID(sid).Groups([]*SchemaGroup{sg}).MustBuild(), + LF: LinkableFields{ + URL: &SchemaFieldPointer{ + Field: id.PropertySchemaFieldID("xx"), + }, + }, Expected: false, }, { - Name: "invalid: Lng", - S: NewSchema().ID(sid).Groups([]*SchemaGroup{sg}).MustBuild(), - LF: LinkableFields{LatLng: NewPointer(nil, nil, id.PropertySchemaFieldID("xx").Ref())}, + Name: "invalid: Lng", + S: NewSchema().ID(sid).Groups([]*SchemaGroup{sg}).MustBuild(), + LF: LinkableFields{ + LatLng: &SchemaFieldPointer{ + Field: id.PropertySchemaFieldID("xx"), + }, + }, Expected: false, }, { @@ -297,35 +66,3 @@ func TestLinkableField_Validate(t *testing.T) { }) } } - -func TestSchemaGroupAndField_IsEmpty(t *testing.T) { - tests := []struct { - name string - target SchemaGroupAndField - want bool - }{ - { - name: "present", - target: SchemaGroupAndField{ - Group: testSchemaGroup1, - Field: testSchemaField1, - }, - want: false, - }, - { - name: "empty", - target: SchemaGroupAndField{}, - want: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gf := SchemaGroupAndField{ - Group: tt.target.Group, - Field: tt.target.Field, - } - assert.Equal(t, tt.want, gf.IsEmpty()) - }) - } -} From d8424301fd070d82ae73d6cb0366151b99712c40 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 7 Dec 2021 16:00:55 +0900 Subject: [PATCH 13/55] rename CollectDatasets --- pkg/property/field.go | 2 +- pkg/property/field_test.go | 4 ++-- pkg/property/group.go | 4 ++-- pkg/property/group_list.go | 4 ++-- pkg/property/group_list_test.go | 4 ++-- pkg/property/group_test.go | 4 ++-- pkg/property/item.go | 2 +- pkg/property/property.go | 4 ++-- pkg/scene/sceneops/plugin_migrator.go | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/pkg/property/field.go b/pkg/property/field.go index cc94b623..d7e9a8a3 100644 --- a/pkg/property/field.go +++ b/pkg/property/field.go @@ -71,7 +71,7 @@ func (p *Field) ActualValue(ds *dataset.Dataset) *ValueAndDatasetValue { return NewValueAndDatasetValue(p.Type(), dv, p.Value()) } -func (p *Field) CollectDatasets() []id.DatasetID { +func (p *Field) Datasets() []id.DatasetID { if p == nil { return nil } diff --git a/pkg/property/field_test.go b/pkg/property/field_test.go index a2a75ba1..446330d4 100644 --- a/pkg/property/field_test.go +++ b/pkg/property/field_test.go @@ -61,7 +61,7 @@ func TestField_ActualValue(t *testing.T) { } } -func TestField_CollectDatasets(t *testing.T) { +func TestField_Datasets(t *testing.T) { p := NewSchemaField().ID("A").Type(ValueTypeString).MustBuild() dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() @@ -89,7 +89,7 @@ func TestField_CollectDatasets(t *testing.T) { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() - res := tc.Field.CollectDatasets() + res := tc.Field.Datasets() assert.Equal(tt, tc.Expected, res) }) } diff --git a/pkg/property/group.go b/pkg/property/group.go index d0a7c5bb..03ed46ce 100644 --- a/pkg/property/group.go +++ b/pkg/property/group.go @@ -71,14 +71,14 @@ func (g *Group) HasLinkedField() bool { return false } -func (g *Group) CollectDatasets() []id.DatasetID { +func (g *Group) Datasets() []id.DatasetID { if g == nil { return nil } res := []id.DatasetID{} for _, f := range g.fields { - res = append(res, f.CollectDatasets()...) + res = append(res, f.Datasets()...) } return res diff --git a/pkg/property/group_list.go b/pkg/property/group_list.go index a05e514e..ea759433 100644 --- a/pkg/property/group_list.go +++ b/pkg/property/group_list.go @@ -70,14 +70,14 @@ func (g *GroupList) HasLinkedField() bool { return false } -func (g *GroupList) CollectDatasets() []id.DatasetID { +func (g *GroupList) Datasets() []id.DatasetID { if g == nil { return nil } res := []id.DatasetID{} for _, f := range g.groups { - res = append(res, f.CollectDatasets()...) + res = append(res, f.Datasets()...) } return res diff --git a/pkg/property/group_list_test.go b/pkg/property/group_list_test.go index dd120340..c4e9e3dd 100644 --- a/pkg/property/group_list_test.go +++ b/pkg/property/group_list_test.go @@ -80,7 +80,7 @@ func TestGroupList_HasLinkedField(t *testing.T) { } } -func TestGroupList_CollectDatasets(t *testing.T) { +func TestGroupList_Datasets(t *testing.T) { pid := id.NewPropertyItemID() sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") @@ -112,7 +112,7 @@ func TestGroupList_CollectDatasets(t *testing.T) { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() - assert.Equal(tt, tc.Expected, tc.GL.CollectDatasets()) + assert.Equal(tt, tc.Expected, tc.GL.Datasets()) }) } } diff --git a/pkg/property/group_test.go b/pkg/property/group_test.go index 3b31b30b..c0ac8e95 100644 --- a/pkg/property/group_test.go +++ b/pkg/property/group_test.go @@ -108,7 +108,7 @@ func TestGroup_IsDatasetLinked(t *testing.T) { } } -func TestGroup_CollectDatasets(t *testing.T) { +func TestGroup_Datasets(t *testing.T) { sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() @@ -136,7 +136,7 @@ func TestGroup_CollectDatasets(t *testing.T) { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() - res := tc.Group.CollectDatasets() + res := tc.Group.Datasets() assert.Equal(tt, tc.Expected, res) }) } diff --git a/pkg/property/item.go b/pkg/property/item.go index b26055e1..506fee0c 100644 --- a/pkg/property/item.go +++ b/pkg/property/item.go @@ -15,7 +15,7 @@ type Item interface { Schema() id.PropertySchemaID SchemaRef() *id.PropertySchemaID HasLinkedField() bool - CollectDatasets() []id.DatasetID + Datasets() []id.DatasetID FieldsByLinkedDataset(id.DatasetSchemaID, id.DatasetID) []*Field IsDatasetLinked(id.DatasetSchemaID, id.DatasetID) bool IsEmpty() bool diff --git a/pkg/property/property.go b/pkg/property/property.go index 03ebd7a7..eacdebd7 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -184,14 +184,14 @@ func (p *Property) IsDatasetLinked(s id.DatasetSchemaID, i id.DatasetID) bool { return false } -func (p *Property) CollectDatasets() []id.DatasetID { +func (p *Property) Datasets() []id.DatasetID { if p == nil { return nil } res := []id.DatasetID{} for _, f := range p.items { - res = append(res, f.CollectDatasets()...) + res = append(res, f.Datasets()...) } return res diff --git a/pkg/scene/sceneops/plugin_migrator.go b/pkg/scene/sceneops/plugin_migrator.go index 2971b996..cb3b68ae 100644 --- a/pkg/scene/sceneops/plugin_migrator.go +++ b/pkg/scene/sceneops/plugin_migrator.go @@ -237,7 +237,7 @@ func (s *PluginMigrator) MigratePlugins(ctx context.Context, sc *scene.Scene, ol func collectDatasetIDs(properties []*property.Property) []id.DatasetID { res := []id.DatasetID{} for _, p := range properties { - res = append(res, p.CollectDatasets()...) + res = append(res, p.Datasets()...) } return res } From f353372f288b095770d445322f61ad1e3744171c Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 7 Dec 2021 16:07:56 +0900 Subject: [PATCH 14/55] remove extra fields from property.Item --- pkg/layer/decoding/reearth_test.go | 4 +-- pkg/property/group.go | 21 --------------- pkg/property/group_list.go | 21 --------------- pkg/property/group_list_test.go | 42 +++--------------------------- pkg/property/group_test.go | 10 ------- pkg/property/item.go | 5 +--- pkg/property/merged.go | 4 +-- 7 files changed, 9 insertions(+), 98 deletions(-) diff --git a/pkg/layer/decoding/reearth_test.go b/pkg/layer/decoding/reearth_test.go index 29b78151..52d85ed6 100644 --- a/pkg/layer/decoding/reearth_test.go +++ b/pkg/layer/decoding/reearth_test.go @@ -183,7 +183,7 @@ func TestReearthDecoder_Decode(t *testing.T) { SchemaItem: id.PropertySchemaGroupID("hoge"), Groups: []*property.InitializerGroup{ { - ID: property.ToGroupList(prop.Items()[0]).GroupAt(0).IDRef(), + ID: property.ToGroupList(prop.Items()[0]).GroupAt(0).ID().Ref(), Fields: []*property.InitializerField{ { Field: id.PropertySchemaFieldID("foobar"), @@ -193,7 +193,7 @@ func TestReearthDecoder_Decode(t *testing.T) { }, }, { - ID: property.ToGroupList(prop.Items()[0]).GroupAt(1).IDRef(), + ID: property.ToGroupList(prop.Items()[0]).GroupAt(1).ID().Ref(), Fields: []*property.InitializerField{ { Field: id.PropertySchemaFieldID("foobar"), diff --git a/pkg/property/group.go b/pkg/property/group.go index 03ed46ce..627aa409 100644 --- a/pkg/property/group.go +++ b/pkg/property/group.go @@ -24,13 +24,6 @@ func (g *Group) ID() id.PropertyItemID { return g.itemBase.ID } -func (g *Group) IDRef() *id.PropertyItemID { - if g == nil { - return nil - } - return g.itemBase.ID.Ref() -} - func (g *Group) SchemaGroup() id.PropertySchemaGroupID { if g == nil { return id.PropertySchemaGroupID("") @@ -38,13 +31,6 @@ func (g *Group) SchemaGroup() id.PropertySchemaGroupID { return g.itemBase.SchemaGroup } -func (g *Group) SchemaGroupRef() *id.PropertySchemaGroupID { - if g == nil { - return nil - } - return g.itemBase.SchemaGroup.Ref() -} - func (g *Group) Schema() id.PropertySchemaID { if g == nil { return id.PropertySchemaID{} @@ -52,13 +38,6 @@ func (g *Group) Schema() id.PropertySchemaID { return g.itemBase.Schema } -func (g *Group) SchemaRef() *id.PropertySchemaID { - if g == nil { - return nil - } - return g.itemBase.Schema.Ref() -} - func (g *Group) HasLinkedField() bool { if g == nil { return false diff --git a/pkg/property/group_list.go b/pkg/property/group_list.go index ea759433..b964d169 100644 --- a/pkg/property/group_list.go +++ b/pkg/property/group_list.go @@ -23,13 +23,6 @@ func (g *GroupList) ID() id.PropertyItemID { return g.itemBase.ID } -func (g *GroupList) IDRef() *id.PropertyItemID { - if g == nil { - return nil - } - return g.itemBase.ID.Ref() -} - func (g *GroupList) SchemaGroup() id.PropertySchemaGroupID { if g == nil { return id.PropertySchemaGroupID("") @@ -37,13 +30,6 @@ func (g *GroupList) SchemaGroup() id.PropertySchemaGroupID { return g.itemBase.SchemaGroup } -func (g *GroupList) SchemaGroupRef() *id.PropertySchemaGroupID { - if g == nil { - return nil - } - return g.itemBase.SchemaGroup.Ref() -} - func (g *GroupList) Schema() id.PropertySchemaID { if g == nil { return id.PropertySchemaID{} @@ -51,13 +37,6 @@ func (g *GroupList) Schema() id.PropertySchemaID { return g.itemBase.Schema } -func (g *GroupList) SchemaRef() *id.PropertySchemaID { - if g == nil { - return nil - } - return g.itemBase.Schema.Ref() -} - func (g *GroupList) HasLinkedField() bool { if g == nil { return false diff --git a/pkg/property/group_list_test.go b/pkg/property/group_list_test.go index c4e9e3dd..cc1e66d8 100644 --- a/pkg/property/group_list_test.go +++ b/pkg/property/group_list_test.go @@ -8,40 +8,6 @@ import ( "github.com/stretchr/testify/assert" ) -func TestGroupList_IDRef(t *testing.T) { - var b *GroupList - assert.Nil(t, b.IDRef()) - b = NewGroupList().NewID().MustBuild() - assert.NotNil(t, b.IDRef()) -} - -func TestGroupList_SchemaRef(t *testing.T) { - testCases := []struct { - Name string - GL *GroupList - ExpectedSG *id.PropertySchemaGroupID - ExpectedSchema *id.PropertySchemaID - }{ - { - Name: "nil group list", - }, - { - Name: "success", - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), id.PropertySchemaGroupID("xx")).MustBuild(), - ExpectedSG: id.PropertySchemaGroupID("xx").Ref(), - ExpectedSchema: id.MustPropertySchemaID("xx~1.0.0/aa").Ref(), - }, - } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - assert.Equal(tt, tc.ExpectedSG, tc.GL.SchemaGroupRef()) - assert.Equal(tt, tc.ExpectedSchema, tc.GL.SchemaRef()) - }) - } -} - func TestGroupList_HasLinkedField(t *testing.T) { pid := id.NewPropertyItemID() sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() @@ -669,7 +635,7 @@ func TestGroupList_GetOrCreateField(t *testing.T) { Name: "success", GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").Groups([]*Group{g}).MustBuild(), Schema: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), - Ptr: NewPointer(nil, g.IDRef(), sf.ID().Ref()), + Ptr: NewPointer(nil, g.ID().Ref(), sf.ID().Ref()), Expected: struct { Ok bool Field *Field @@ -682,19 +648,19 @@ func TestGroupList_GetOrCreateField(t *testing.T) { Name: "can't get a group", GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").MustBuild(), Schema: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), - Ptr: NewPointer(nil, g.IDRef(), sf.ID().Ref()), + Ptr: NewPointer(nil, g.ID().Ref(), sf.ID().Ref()), }, { Name: "FieldByItem not ok: sg!=nil", GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").Groups([]*Group{g}).MustBuild(), Schema: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), - Ptr: NewPointer(sg.IDRef(), g.IDRef(), sf.ID().Ref()), + Ptr: NewPointer(sg.IDRef(), g.ID().Ref(), sf.ID().Ref()), }, { Name: "psg == nil", GL: NewGroupList().NewID().Groups([]*Group{g}).MustBuild(), Schema: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), - Ptr: NewPointer(nil, g.IDRef(), sf.ID().Ref()), + Ptr: NewPointer(nil, g.ID().Ref(), sf.ID().Ref()), }, } diff --git a/pkg/property/group_test.go b/pkg/property/group_test.go index c0ac8e95..ffa7e938 100644 --- a/pkg/property/group_test.go +++ b/pkg/property/group_test.go @@ -9,22 +9,12 @@ import ( "github.com/stretchr/testify/assert" ) -func TestGroup_IDRef(t *testing.T) { - gid := id.NewPropertyItemID() - var g *Group - assert.Nil(t, g.IDRef()) - g = NewGroup().ID(gid).MustBuild() - assert.Equal(t, gid.Ref(), g.IDRef()) -} - func TestGroup_SchemaGroup(t *testing.T) { var g *Group - assert.Nil(t, g.SchemaGroupRef()) assert.Equal(t, id.PropertySchemaGroupID(""), g.SchemaGroup()) pfid := id.PropertySchemaGroupID("aa") g = NewGroup().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), pfid).MustBuild() assert.Equal(t, pfid, g.SchemaGroup()) - assert.Equal(t, pfid.Ref(), g.SchemaGroupRef()) } func TestGroup_HasLinkedField(t *testing.T) { diff --git a/pkg/property/item.go b/pkg/property/item.go index 506fee0c..095a18ba 100644 --- a/pkg/property/item.go +++ b/pkg/property/item.go @@ -9,14 +9,11 @@ import ( type Item interface { ID() id.PropertyItemID - IDRef() *id.PropertyItemID SchemaGroup() id.PropertySchemaGroupID - SchemaGroupRef() *id.PropertySchemaGroupID Schema() id.PropertySchemaID - SchemaRef() *id.PropertySchemaID + FieldsByLinkedDataset(id.DatasetSchemaID, id.DatasetID) []*Field HasLinkedField() bool Datasets() []id.DatasetID - FieldsByLinkedDataset(id.DatasetSchemaID, id.DatasetID) []*Field IsDatasetLinked(id.DatasetSchemaID, id.DatasetID) bool IsEmpty() bool Prune() diff --git a/pkg/property/merged.go b/pkg/property/merged.go index a9e8e180..afe74041 100644 --- a/pkg/property/merged.go +++ b/pkg/property/merged.go @@ -216,11 +216,11 @@ func mergeItem(o, p Item, linked *id.DatasetID) *MergedGroup { var oid, pid *id.PropertyItemID var sg id.PropertySchemaGroupID if o != nil { - oid = o.IDRef() + oid = o.ID().Ref() sg = o.SchemaGroup() } if p != nil { - pid = p.IDRef() + pid = p.ID().Ref() sg = p.SchemaGroup() } From 54a804d41ea61ef56ae6d971d640683579eec5c6 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 7 Dec 2021 18:35:58 +0900 Subject: [PATCH 15/55] add Clone, Fields, RemoveFields to property --- .../adapter/gql/gqlmodel/convert_property.go | 2 +- .../infrastructure/mongo/mongodoc/property.go | 2 +- pkg/property/field_test.go | 5 + pkg/property/group.go | 74 ++++++- pkg/property/group_builder_test.go | 4 +- pkg/property/group_list.go | 87 +++++++++ pkg/property/group_list_test.go | 177 ++++++++++++++++- pkg/property/group_test.go | 180 +++++++++++++++++- pkg/property/item.go | 3 + pkg/property/migrator.go | 2 +- pkg/property/property.go | 38 ++++ pkg/property/property_test.go | 137 ++++++++++++- 12 files changed, 692 insertions(+), 19 deletions(-) diff --git a/internal/adapter/gql/gqlmodel/convert_property.go b/internal/adapter/gql/gqlmodel/convert_property.go index 70e800e7..b1ddc377 100644 --- a/internal/adapter/gql/gqlmodel/convert_property.go +++ b/internal/adapter/gql/gqlmodel/convert_property.go @@ -398,7 +398,7 @@ func ToPropertyGroup(g *property.Group, p *property.Property, gl *property.Group return nil } - gfields := g.Fields() + gfields := g.Fields(nil) fields := make([]*PropertyField, 0, len(gfields)) for _, f := range gfields { fields = append(fields, ToPropertyField(f, p, gl, g)) diff --git a/internal/infrastructure/mongo/mongodoc/property.go b/internal/infrastructure/mongo/mongodoc/property.go index 8e332634..28f28939 100644 --- a/internal/infrastructure/mongo/mongodoc/property.go +++ b/internal/infrastructure/mongo/mongodoc/property.go @@ -133,7 +133,7 @@ func newPropertyItem(f property.Item) *PropertyItemDocument { if g := property.ToGroup(f); g != nil { t = typePropertyItemGroup - pfields := g.Fields() + pfields := g.Fields(nil) fields = make([]*PropertyFieldDocument, 0, len(pfields)) for _, r := range pfields { fields = append(fields, newPropertyField(r)) diff --git a/pkg/property/field_test.go b/pkg/property/field_test.go index 446330d4..e0705e5d 100644 --- a/pkg/property/field_test.go +++ b/pkg/property/field_test.go @@ -8,6 +8,11 @@ import ( "github.com/stretchr/testify/assert" ) +var ( + testField1 = NewField(testSchemaField1).Value(OptionalValueFrom(ValueTypeString.ValueFrom("aaa"))).MustBuild() + testField2 = NewField(testSchemaField3).Value(NewOptionalValue(ValueTypeLatLng, nil)).MustBuild() +) + func TestField_ActualValue(t *testing.T) { p := NewSchemaField().ID("A").Type(ValueTypeString).MustBuild() dsid := id.NewDatasetID() diff --git a/pkg/property/group.go b/pkg/property/group.go index 627aa409..994fde7b 100644 --- a/pkg/property/group.go +++ b/pkg/property/group.go @@ -161,7 +161,7 @@ func (g *Group) RemoveField(fid id.PropertySchemaFieldID) { if g == nil { return } - for i, f := range g.fields { + for i, f := range g.Fields(nil) { if f.Field() == fid { g.fields = append(g.fields[:i], g.fields[i+1:]...) return @@ -180,14 +180,6 @@ func (g *Group) FieldIDs() []id.PropertySchemaFieldID { return fields } -// Fields returns a slice of fields -func (g *Group) Fields() []*Field { - if g == nil { - return nil - } - return append([]*Field{}, g.fields...) -} - // Field returns a field whose id is specified func (g *Group) Field(fid id.PropertySchemaFieldID) *Field { if g == nil { @@ -238,3 +230,67 @@ func (p *Group) ValidateSchema(ps *SchemaGroup) error { return nil } + +func (p *Group) Clone() *Group { + if p == nil { + return nil + } + fields := make([]*Field, 0, len(p.fields)) + for _, f := range p.fields { + fields = append(fields, f.Clone()) + } + return &Group{ + fields: fields, + itemBase: p.itemBase, + } +} + +func (p *Group) CloneItem() Item { + return p.Clone() +} + +func (g *Group) Fields(p *Pointer) []*Field { + if g == nil || len(g.fields) == 0 { + return nil + } + + if p == nil { + return append(g.fields[:0:0], g.fields...) + } + + fid, ok := p.Field() + if !ok { + if sgid, ok := p.ItemBySchemaGroup(); ok { + if sgid == g.SchemaGroup() { + return g.Fields(nil) + } + return nil + } + + if iid, ok := p.Item(); ok { + if iid == g.ID() { + return g.Fields(nil) + } + return nil + } + + return nil + } + + if f := g.Field(fid); f != nil { + return []*Field{f} + } + + return nil +} + +func (g *Group) RemoveFields(ptr *Pointer) { + if g == nil || ptr == nil { + return + } + f, ok := ptr.Field() + if !ok { + return + } + g.RemoveField(f) +} diff --git a/pkg/property/group_builder_test.go b/pkg/property/group_builder_test.go index 504a3754..79d00766 100644 --- a/pkg/property/group_builder_test.go +++ b/pkg/property/group_builder_test.go @@ -59,7 +59,7 @@ func TestGroupBuilder_Build(t *testing.T) { tt.Parallel() res, err := NewGroup().ID(tc.Id).Fields(tc.Fields).Schema(tc.Schema, tc.SchemaGroup).Build() if err == nil { - assert.Equal(tt, tc.Expected.Fields, res.Fields()) + assert.Equal(tt, tc.Expected.Fields, res.Fields(nil)) assert.Equal(tt, tc.Expected.Schema, res.Schema()) assert.Equal(tt, tc.Expected.SchemaGroup, res.SchemaGroup()) assert.Equal(tt, tc.Expected.Id, res.ID()) @@ -128,7 +128,7 @@ func TestGroupBuilder_MustBuild(t *testing.T) { res = NewGroup().ID(tc.Id).Fields(tc.Fields).Schema(tc.Schema, tc.SchemaGroup).MustBuild() } else { res = NewGroup().ID(tc.Id).Fields(tc.Fields).Schema(tc.Schema, tc.SchemaGroup).MustBuild() - assert.Equal(tt, tc.Expected.Fields, res.Fields()) + assert.Equal(tt, tc.Expected.Fields, res.Fields(nil)) assert.Equal(tt, tc.Expected.Schema, res.Schema()) assert.Equal(tt, tc.Expected.SchemaGroup, res.SchemaGroup()) assert.Equal(tt, tc.Expected.Id, res.ID()) diff --git a/pkg/property/group_list.go b/pkg/property/group_list.go index b964d169..d852a863 100644 --- a/pkg/property/group_list.go +++ b/pkg/property/group_list.go @@ -332,3 +332,90 @@ func (p *GroupList) ValidateSchema(ps *SchemaGroup) error { return nil } + +func (p *GroupList) Clone() *GroupList { + if p == nil { + return nil + } + groups := make([]*Group, 0, len(p.groups)) + for _, g := range p.groups { + groups = append(groups, g.Clone()) + } + return &GroupList{ + groups: groups, + itemBase: p.itemBase, + } +} + +func (p *GroupList) CloneItem() Item { + return p.Clone() +} + +func (g *GroupList) Fields(ptr *Pointer) []*Field { + if g == nil || len(g.groups) == 0 { + return nil + } + + var fields []*Field + if ptr == nil { + for _, g := range g.groups { + if f := g.Fields(nil); len(f) > 0 { + fields = append(fields, f...) + } + } + return fields + } + + if pi, ok := ptr.Item(); ok { + if g.ID() == pi { + return g.Fields(nil) + } + return g.GetGroup(pi).Fields(ptr) + } + + if psg, ok := ptr.ItemBySchemaGroup(); ok && psg == g.SchemaGroup() { + fields = make([]*Field, 0, len(g.groups)) + for _, g := range g.groups { + if f := g.Fields(ptr); len(f) > 0 { + fields = append(fields, f...) + } + } + return fields + } + + if fid, ok := ptr.Field(); ok { + fields = make([]*Field, 0, len(g.groups)) + for _, g := range g.groups { + if f := g.Field(fid); f != nil { + fields = append(fields, f) + } + } + return fields + } + + return nil +} + +func (g *GroupList) RemoveFields(ptr *Pointer) { + if g == nil { + return + } + + if i, f, ok := ptr.FieldByItem(); ok { + g.GetGroup(i).RemoveField(f) + return + } + + if psg, pf, ok := ptr.FieldBySchemaGroup(); ok && psg == g.SchemaGroup() { + for _, g := range g.groups { + g.RemoveField(pf) + } + return + } + + if fid, ok := ptr.Field(); ok { + for _, g := range g.groups { + g.RemoveField(fid) + } + } +} diff --git a/pkg/property/group_list_test.go b/pkg/property/group_list_test.go index cc1e66d8..18aa5787 100644 --- a/pkg/property/group_list_test.go +++ b/pkg/property/group_list_test.go @@ -8,6 +8,10 @@ import ( "github.com/stretchr/testify/assert" ) +var ( + testGroupList1 = NewGroupList().NewID().Schema(testSchema1.ID(), testSchemaGroup2.ID()).Groups([]*Group{testGroup2}).MustBuild() +) + func TestGroupList_HasLinkedField(t *testing.T) { pid := id.NewPropertyItemID() sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() @@ -702,8 +706,179 @@ func TestGroupList_CreateAndAddListItem(t *testing.T) { tt.Parallel() res := tc.GL.CreateAndAddListItem(tc.Schema, tc.Index) assert.Equal(tt, tc.Expected.Schema(), res.Schema()) - assert.Equal(tt, tc.Expected.Fields(), res.Fields()) + assert.Equal(tt, tc.Expected.Fields(nil), res.Fields(nil)) assert.Equal(tt, tc.Expected.SchemaGroup(), res.SchemaGroup()) }) } } + +func TestGroupList_Clone(t *testing.T) { + tests := []struct { + name string + target *GroupList + n bool + }{ + { + name: "ok", + target: testGroupList1.Clone(), + }, + { + name: "nil", + n: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := tt.target.Clone() + if tt.n { + assert.Nil(t, res) + } else { + assert.Equal(t, tt.target, res) + assert.NotSame(t, tt.target, res) + } + }) + } +} + +func TestGroupList_CloneItem(t *testing.T) { + tests := []struct { + name string + target *GroupList + n bool + }{ + { + name: "ok", + target: testGroupList1.Clone(), + }, + { + name: "nil", + n: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := tt.target.CloneItem() + if tt.n { + assert.Nil(t, res) + } else { + assert.Equal(t, tt.target, res) + assert.NotSame(t, tt.target, res) + } + }) + } +} + +func TestGroupList_Fields(t *testing.T) { + type args struct { + p *Pointer + } + tests := []struct { + name string + target *GroupList + args args + want []*Field + }{ + { + name: "all", + target: testGroupList1, + args: args{p: nil}, + want: []*Field{testField2}, + }, + { + name: "specified", + target: testGroupList1, + args: args{p: PointFieldOnly(testField2.Field())}, + want: []*Field{testField2}, + }, + { + name: "not found", + target: testGroupList1, + args: args{p: PointFieldOnly("xxxxxx")}, + want: []*Field{}, + }, + { + name: "empty", + target: &GroupList{}, + args: args{p: PointFieldOnly(testField2.Field())}, + want: nil, + }, + { + name: "nil", + target: nil, + args: args{p: PointFieldOnly(testField2.Field())}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Fields(tt.args.p)) + }) + } +} + +func TestGroupList_RemoveFields(t *testing.T) { + type args struct { + p *Pointer + } + tests := []struct { + name string + target *GroupList + args args + want []*Field + }{ + { + name: "nil pointer", + target: testGroupList1.Clone(), + args: args{p: nil}, + want: []*Field{testField2}, + }, + { + name: "specified", + target: testGroupList1.Clone(), + args: args{p: PointFieldOnly(testField2.Field())}, + want: nil, + }, + { + name: "specified schema group", + target: testGroupList1.Clone(), + args: args{p: PointItemBySchema(testGroupList1.SchemaGroup())}, + want: nil, + }, + { + name: "specified item", + target: testGroupList1.Clone(), + args: args{p: PointItem(testGroupList1.ID())}, + want: nil, + }, + { + name: "not found", + target: testGroupList1.Clone(), + args: args{p: PointFieldOnly("xxxxxx")}, + want: []*Field{testField2}, + }, + { + name: "empty", + target: &GroupList{}, + args: args{p: PointFieldOnly(testField1.Field())}, + want: nil, + }, + { + name: "nil", + target: nil, + args: args{p: PointFieldOnly(testField1.Field())}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.target.RemoveFields(tt.args.p) + if tt.target != nil { + assert.Equal(t, tt.want, tt.target.Fields(nil)) + } + }) + } +} diff --git a/pkg/property/group_test.go b/pkg/property/group_test.go index ffa7e938..2d9eba16 100644 --- a/pkg/property/group_test.go +++ b/pkg/property/group_test.go @@ -9,6 +9,11 @@ import ( "github.com/stretchr/testify/assert" ) +var ( + testGroup1 = NewGroup().NewID().Schema(testSchema1.ID(), testSchemaGroup1.ID()).Fields([]*Field{testField1}).MustBuild() + testGroup2 = NewGroup().NewID().Schema(testSchema1.ID(), testSchemaGroup2.ID()).Fields([]*Field{testField2}).MustBuild() +) + func TestGroup_SchemaGroup(t *testing.T) { var g *Group assert.Equal(t, id.PropertySchemaGroupID(""), g.SchemaGroup()) @@ -228,7 +233,7 @@ func TestGroup_Prune(t *testing.T) { t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() tc.Group.Prune() - assert.Equal(tt, tc.Expected, tc.Group.Fields()) + assert.Equal(tt, tc.Expected, tc.Group.Fields(nil)) }) } } @@ -326,7 +331,7 @@ func TestGroup_RemoveField(t *testing.T) { t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() tc.Group.RemoveField(tc.Input) - assert.Equal(tt, tc.Expected, tc.Group.Fields()) + assert.Equal(tt, tc.Expected, tc.Group.Fields(nil)) }) } } @@ -460,3 +465,174 @@ func TestGroup_UpdateNameFieldValue(t *testing.T) { }) } } + +func TestGroup_Clone(t *testing.T) { + tests := []struct { + name string + target *Group + n bool + }{ + { + name: "ok", + target: testGroup1.Clone(), + }, + { + name: "nil", + n: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := tt.target.Clone() + if tt.n { + assert.Nil(t, res) + } else { + assert.Equal(t, tt.target, res) + assert.NotSame(t, tt.target, res) + } + }) + } +} + +func TestGroup_CloneItem(t *testing.T) { + tests := []struct { + name string + target *Group + n bool + }{ + { + name: "ok", + target: testGroup1.Clone(), + }, + { + name: "nil", + n: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := tt.target.CloneItem() + if tt.n { + assert.Nil(t, res) + } else { + assert.Equal(t, tt.target, res) + assert.NotSame(t, tt.target, res) + } + }) + } +} + +func TestGroup_Fields(t *testing.T) { + type args struct { + p *Pointer + } + tests := []struct { + name string + target *Group + args args + want []*Field + }{ + { + name: "all", + target: testGroup1, + args: args{p: nil}, + want: []*Field{testField1}, + }, + { + name: "specified", + target: testGroup1, + args: args{p: PointFieldOnly(testField1.Field())}, + want: []*Field{testField1}, + }, + { + name: "specified schema group", + target: testGroup1, + args: args{p: PointItemBySchema(testGroup1.SchemaGroup())}, + want: []*Field{testField1}, + }, + { + name: "specified item", + target: testGroup1, + args: args{p: PointItem(testGroup1.ID())}, + want: []*Field{testField1}, + }, + { + name: "not found", + target: testGroup1, + args: args{p: PointFieldOnly("xxxxxx")}, + want: nil, + }, + { + name: "empty", + target: &Group{}, + args: args{p: PointFieldOnly(testField1.Field())}, + want: nil, + }, + { + name: "nil", + target: nil, + args: args{p: PointFieldOnly(testField1.Field())}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Fields(tt.args.p)) + }) + } +} + +func TestGroup_RemoveFields(t *testing.T) { + type args struct { + p *Pointer + } + tests := []struct { + name string + target *Group + args args + want []*Field + }{ + { + name: "nil pointer", + target: testGroup1.Clone(), + args: args{p: nil}, + want: []*Field{testField1}, + }, + { + name: "specified", + target: testGroup1.Clone(), + args: args{p: PointFieldOnly(testField1.Field())}, + want: []*Field{}, + }, + { + name: "not found", + target: testGroup1.Clone(), + args: args{p: PointFieldOnly("xxxxxx")}, + want: []*Field{testField1}, + }, + { + name: "empty", + target: &Group{}, + args: args{p: PointFieldOnly(testField1.Field())}, + want: nil, + }, + { + name: "nil", + target: nil, + args: args{p: PointFieldOnly(testField1.Field())}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.target.RemoveFields(tt.args.p) + if tt.target != nil { + assert.Equal(t, tt.want, tt.target.fields) + } + }) + } +} diff --git a/pkg/property/item.go b/pkg/property/item.go index 095a18ba..3bee4461 100644 --- a/pkg/property/item.go +++ b/pkg/property/item.go @@ -19,6 +19,9 @@ type Item interface { Prune() MigrateSchema(context.Context, *Schema, dataset.Loader) ValidateSchema(*SchemaGroup) error + Fields(*Pointer) []*Field + RemoveFields(*Pointer) + CloneItem() Item } type itemBase struct { diff --git a/pkg/property/migrator.go b/pkg/property/migrator.go index 9e38d6d0..21617909 100644 --- a/pkg/property/migrator.go +++ b/pkg/property/migrator.go @@ -66,7 +66,7 @@ func (m *DatasetMigrator) MigrateGroup(ctx context.Context, g *Group) error { if m == nil { return nil } - for _, f := range g.Fields() { + for _, f := range g.Fields(nil) { if err := m.MigrateField(ctx, f); err != nil { return err } diff --git a/pkg/property/property.go b/pkg/property/property.go index eacdebd7..d2c17920 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -161,6 +161,44 @@ func (p *Property) HasLinkedField() bool { return false } +func (p *Property) Clone() *Property { + if p == nil { + return nil + } + + items := make([]Item, 0, len(p.items)) + for _, i := range p.items { + items = append(items, i.CloneItem()) + } + + return &Property{ + id: p.id, + schema: p.schema, + scene: p.scene, + items: items, + } +} + +func (p *Property) Fields(ptr *Pointer) []*Field { + if p == nil || len(p.items) == 0 { + return nil + } + res := []*Field{} + for _, g := range p.items { + res = append(res, g.Fields(ptr)...) + } + return res +} + +func (p *Property) RemoveFields(ptr *Pointer) { + if p == nil { + return + } + for _, g := range p.items { + g.RemoveFields(ptr) + } +} + func (p *Property) FieldsByLinkedDataset(s id.DatasetSchemaID, i id.DatasetID) []*Field { if p == nil { return nil diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index 8b375104..9cc311b9 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -10,6 +10,10 @@ import ( "github.com/stretchr/testify/assert" ) +var ( + testProperty1 = New().NewID().Schema(testSchema1.ID()).Scene(id.NewSceneID()).Items([]Item{testGroup1, testGroupList1}).MustBuild() +) + func TestPropertyMigrateSchema(t *testing.T) { sceneID := id.NewSceneID() oldSchema, _ := id.PropertySchemaIDFrom("hoge~1.0.0/test") @@ -103,7 +107,7 @@ func TestPropertyMigrateSchema(t *testing.T) { property.MigrateSchema(context.Background(), schema, dataset.LoaderFrom([]*dataset.Dataset{ds})) newGroup := ToGroup(property.ItemBySchema(schemaGroupID)) - newFields := newGroup.Fields() + newFields := newGroup.Fields(nil) assert.Equal(t, schema.ID(), property.Schema()) assert.Equal(t, 1, len(property.Items())) @@ -191,7 +195,7 @@ func TestGetOrCreateField(t *testing.T) { i := ToGroup(p.ItemBySchema(sg1id)) assert.Equal(t, sid, i.Schema()) assert.Equal(t, sg1id, i.SchemaGroup()) - assert.Equal(t, []*Field{f}, i.Fields()) + assert.Equal(t, []*Field{f}, i.Fields(nil)) field, _, _ := p.Field(PointFieldBySchemaGroup(sg1id, sf1id)) assert.Equal(t, f, field) @@ -273,3 +277,132 @@ func TestRemoveListItem(t *testing.T) { assert.Equal(t, []*Group{}, gl.Groups()) assert.Equal(t, 0, len(p.Items())) } + +func TestProperty_Clone(t *testing.T) { + tests := []struct { + name string + target *Property + n bool + }{ + { + name: "ok", + target: testProperty1, + }, + { + name: "nil", + target: nil, + n: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := tt.target.Clone() + if tt.n { + assert.Nil(t, tt.target) + } else { + assert.Equal(t, tt.target, res) + assert.NotSame(t, tt.target, res) + } + }) + } +} + +func TestProperty_Fields(t *testing.T) { + type args struct { + p *Pointer + } + tests := []struct { + name string + target *Property + args args + want []*Field + }{ + { + name: "all", + target: testProperty1, + args: args{p: nil}, + want: []*Field{testField1, testField2}, + }, + { + name: "specified", + target: testProperty1, + args: args{p: PointFieldOnly(testField1.Field())}, + want: []*Field{testField1}, + }, + { + name: "not found", + target: testProperty1, + args: args{p: PointFieldOnly("xxxxxx")}, + want: []*Field{}, + }, + { + name: "empty", + target: &Property{}, + args: args{p: PointFieldOnly(testField1.Field())}, + want: nil, + }, + { + name: "nil", + target: nil, + args: args{p: PointFieldOnly(testField1.Field())}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Fields(tt.args.p)) + }) + } +} + +func TestProperty_RemoveFields(t *testing.T) { + type args struct { + p *Pointer + } + tests := []struct { + name string + args args + target *Property + want []*Field + }{ + { + name: "nil pointer", + target: testProperty1.Clone(), + args: args{p: nil}, + want: []*Field{testField1, testField2}, + }, + { + name: "specified", + target: testProperty1.Clone(), + args: args{p: PointFieldOnly(testField1.Field())}, + want: []*Field{testField2}, + }, + { + name: "not found", + target: testProperty1.Clone(), + args: args{p: PointFieldOnly("xxxxxx")}, + want: []*Field{testField1, testField2}, + }, + { + name: "empty", + target: &Property{}, + args: args{p: PointFieldOnly(testField1.Field())}, + want: nil, + }, + { + name: "nil", + target: nil, + args: args{p: PointFieldOnly(testField1.Field())}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.target.RemoveFields(tt.args.p) + assert.Equal(t, tt.want, tt.target.Fields(nil)) + }) + } +} From 51f05e63cfa582b55f16b28d309d10d8dc0ff88d Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 8 Dec 2021 20:22:49 +0900 Subject: [PATCH 16/55] rename GetGroup --- pkg/property/group_list.go | 4 ++-- pkg/property/group_list_test.go | 2 +- pkg/property/property.go | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/property/group_list.go b/pkg/property/group_list.go index d852a863..e4decc71 100644 --- a/pkg/property/group_list.go +++ b/pkg/property/group_list.go @@ -119,7 +119,7 @@ func (g *GroupList) Groups() []*Group { return append([]*Group{}, g.groups...) } -func (g *GroupList) GetGroup(gid id.PropertyItemID) *Group { +func (g *GroupList) Group(gid id.PropertyItemID) *Group { if g == nil { return nil } @@ -280,7 +280,7 @@ func (g *GroupList) GetOrCreateField(ps *Schema, ptr *Pointer) (*Field, bool) { return nil, false } - i := g.GetGroup(item) + i := g.Group(item) if i == nil { return nil, false } diff --git a/pkg/property/group_list_test.go b/pkg/property/group_list_test.go index 18aa5787..e60fa096 100644 --- a/pkg/property/group_list_test.go +++ b/pkg/property/group_list_test.go @@ -221,7 +221,7 @@ func TestGroupList_GetGroup(t *testing.T) { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() - assert.Equal(tt, tc.Expected, tc.GL.GetGroup(tc.Input)) + assert.Equal(tt, tc.Expected, tc.GL.Group(tc.Input)) }) } } diff --git a/pkg/property/property.go b/pkg/property/property.go index d2c17920..65913c43 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -71,7 +71,7 @@ func (p *Property) Item(id id.PropertyItemID) (Item, *GroupList) { return f, nil } if gl := ToGroupList(f); gl != nil { - if i := gl.GetGroup(id); i != nil { + if i := gl.Group(id); i != nil { return i, gl } } @@ -132,12 +132,12 @@ func (p *Property) ListItem(ptr *Pointer) (*Group, *GroupList) { } if sgid, i, ok := ptr.ItemBySchemaGroupAndItem(); ok { if item := ToGroupList(p.ItemBySchema(sgid)); item != nil { - return item.GetGroup(i), item + return item.Group(i), item } } else if iid, ok := ptr.Item(); ok { for _, item := range p.items { litem := ToGroupList(item) - if g := litem.GetGroup(iid); g != nil { + if g := litem.Group(iid); g != nil { return g, litem } } From c9cef8ab08ba08d0cd6d5c6616ef4fe3a1f1eadd Mon Sep 17 00:00:00 2001 From: rot1024 Date: Fri, 10 Dec 2021 17:48:58 +0900 Subject: [PATCH 17/55] add MoveFields to property --- pkg/property/group.go | 54 +++----- pkg/property/group_list.go | 64 ++++----- pkg/property/group_list_test.go | 56 +++++++- pkg/property/group_test.go | 52 +++++++ pkg/property/pointer.go | 137 +++++++++++------- pkg/property/pointer_test.go | 239 ++++++++++++++++++++++++++++++++ pkg/property/property.go | 41 ++++-- pkg/property/property_test.go | 126 +++++++++++++++++ 8 files changed, 640 insertions(+), 129 deletions(-) diff --git a/pkg/property/group.go b/pkg/property/group.go index 994fde7b..7ee71743 100644 --- a/pkg/property/group.go +++ b/pkg/property/group.go @@ -153,15 +153,27 @@ func (g *Group) GetOrCreateField(ps *Schema, fid id.PropertySchemaFieldID) (*Fie return nil, false } - g.fields = append(g.fields, field) + g.AddFields(field) return field, true } +func (g *Group) AddFields(fields ...*Field) { + if g == nil || fields == nil { + return + } + for _, f := range fields { + if field := g.Field(f.Field()); field != nil { + g.RemoveField(f.Field()) + } + g.fields = append(g.fields, f) + } +} + func (g *Group) RemoveField(fid id.PropertySchemaFieldID) { if g == nil { return } - for i, f := range g.Fields(nil) { + for i, f := range g.fields { if f.Field() == fid { g.fields = append(g.fields[:i], g.fields[i+1:]...) return @@ -250,47 +262,25 @@ func (p *Group) CloneItem() Item { } func (g *Group) Fields(p *Pointer) []*Field { - if g == nil || len(g.fields) == 0 { - return nil - } - - if p == nil { - return append(g.fields[:0:0], g.fields...) - } - - fid, ok := p.Field() - if !ok { - if sgid, ok := p.ItemBySchemaGroup(); ok { - if sgid == g.SchemaGroup() { - return g.Fields(nil) - } - return nil - } - - if iid, ok := p.Item(); ok { - if iid == g.ID() { - return g.Fields(nil) - } + if g == nil || len(g.fields) == 0 || (p != nil && !p.TestItem(g.SchemaGroup(), g.ID())) { return nil } + if fid, ok := p.Field(); ok { + if f := g.Field(fid); f != nil { + return []*Field{f} + } return nil } - if f := g.Field(fid); f != nil { - return []*Field{f} - } - - return nil + return append(g.fields[:0:0], g.fields...) } func (g *Group) RemoveFields(ptr *Pointer) { if g == nil || ptr == nil { return } - f, ok := ptr.Field() - if !ok { - return + if f, ok := ptr.FieldIfItemIs(g.SchemaGroup(), g.ID()); ok { + g.RemoveField(f) } - g.RemoveField(f) } diff --git a/pkg/property/group_list.go b/pkg/property/group_list.go index e4decc71..79c35b6e 100644 --- a/pkg/property/group_list.go +++ b/pkg/property/group_list.go @@ -123,14 +123,25 @@ func (g *GroupList) Group(gid id.PropertyItemID) *Group { if g == nil { return nil } - for _, f := range g.groups { - if f.ID() == gid { - return f + for _, g := range g.groups { + if g.ID() == gid { + return g } } return nil } +func (g *GroupList) GroupByPointer(ptr *Pointer) *Group { + if g == nil { + return nil + } + gid, ok := ptr.Item() + if !ok { + return nil + } + return g.Group(gid) +} + func (g *GroupList) GroupAt(i int) *Group { if g == nil || i < 0 || i > len(g.groups)-1 { return nil @@ -352,48 +363,25 @@ func (p *GroupList) CloneItem() Item { } func (g *GroupList) Fields(ptr *Pointer) []*Field { - if g == nil || len(g.groups) == 0 { + if g == nil || len(g.groups) == 0 || (ptr != nil && !ptr.TestSchemaGroup(g.SchemaGroup())) { return nil } - var fields []*Field - if ptr == nil { - for _, g := range g.groups { - if f := g.Fields(nil); len(f) > 0 { - fields = append(fields, f...) - } - } - return fields + if pi, ok := ptr.Item(); ok && g.ID() != pi { + return g.Group(pi).Fields(ptr) } - if pi, ok := ptr.Item(); ok { - if g.ID() == pi { - return g.Fields(nil) - } - return g.GetGroup(pi).Fields(ptr) - } - - if psg, ok := ptr.ItemBySchemaGroup(); ok && psg == g.SchemaGroup() { - fields = make([]*Field, 0, len(g.groups)) - for _, g := range g.groups { - if f := g.Fields(ptr); len(f) > 0 { - fields = append(fields, f...) - } - } - return fields + if fid, ok := ptr.Field(); ok { + ptr = PointFieldOnly(fid) } - if fid, ok := ptr.Field(); ok { - fields = make([]*Field, 0, len(g.groups)) - for _, g := range g.groups { - if f := g.Field(fid); f != nil { - fields = append(fields, f) - } + var fields []*Field + for _, g := range g.groups { + if f := g.Fields(ptr); len(f) > 0 { + fields = append(fields, f...) } - return fields } - - return nil + return fields } func (g *GroupList) RemoveFields(ptr *Pointer) { @@ -401,8 +389,8 @@ func (g *GroupList) RemoveFields(ptr *Pointer) { return } - if i, f, ok := ptr.FieldByItem(); ok { - g.GetGroup(i).RemoveField(f) + if i, ok := ptr.Item(); ok { + g.Group(i).RemoveFields(ptr) return } diff --git a/pkg/property/group_list_test.go b/pkg/property/group_list_test.go index e60fa096..7378c127 100644 --- a/pkg/property/group_list_test.go +++ b/pkg/property/group_list_test.go @@ -192,7 +192,7 @@ func TestGroupList_Prune(t *testing.T) { } } -func TestGroupList_GetGroup(t *testing.T) { +func TestGroupList_Group(t *testing.T) { pid := id.NewPropertyItemID() g := NewGroup().ID(pid).MustBuild() testCases := []struct { @@ -226,11 +226,61 @@ func TestGroupList_GetGroup(t *testing.T) { } } +func TestGroupList_GroupByPointer(t *testing.T) { + g1 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() + g2 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() + g3 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() + g4 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() + gl := NewGroupList().NewID().Schema(testSchema1.ID(), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild() + + tests := []struct { + Name string + Target *GroupList + Args *Pointer + Expected *Group + }{ + { + Name: "nil", + Target: nil, + Args: PointItem(g3.ID()), + Expected: nil, + }, + { + Name: "nil pointer", + Target: gl, + Args: nil, + Expected: nil, + }, + { + Name: "not found", + Target: gl, + Args: PointItem(NewItemID()), + Expected: nil, + }, + { + Name: "found", + Target: gl, + Args: PointItem(g3.ID()), + Expected: g3, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.Expected, tt.Target.GroupByPointer(tt.Args)) + }) + } +} + func TestGroupList_GroupAt(t *testing.T) { g1 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g2 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g3 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g4 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() + gl := NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild() + testCases := []struct { Name string Index int @@ -243,15 +293,17 @@ func TestGroupList_GroupAt(t *testing.T) { { Name: "index < 0", Index: -1, + GL: gl, }, { Name: "index > len(g)-1", Index: 4, + GL: gl, }, { Name: "found", Index: 2, - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + GL: gl, Expected: g3, }, } diff --git a/pkg/property/group_test.go b/pkg/property/group_test.go index 2d9eba16..a086c13a 100644 --- a/pkg/property/group_test.go +++ b/pkg/property/group_test.go @@ -585,6 +585,58 @@ func TestGroup_Fields(t *testing.T) { } } +func TestGroup_AddFields(t *testing.T) { + type args struct { + fields []*Field + } + tests := []struct { + name string + target *Group + args args + want []*Field + }{ + { + name: "nil field", + target: testGroup1.Clone(), + args: args{}, + want: []*Field{testField1}, + }, + { + name: "duplicated", + target: testGroup1.Clone(), + args: args{fields: []*Field{testField1.Clone()}}, + want: []*Field{testField1}, + }, + { + name: "added", + target: testGroup1.Clone(), + args: args{fields: []*Field{testField2.Clone()}}, + want: []*Field{testField1, testField2}, + }, + { + name: "empty", + target: &Group{}, + args: args{fields: []*Field{testField1.Clone()}}, + want: []*Field{testField1}, + }, + { + name: "nil", + target: nil, + args: args{fields: []*Field{testField1.Clone()}}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.target.AddFields(tt.args.fields...) + if tt.target != nil { + assert.Equal(t, tt.want, tt.target.fields) + } + }) + } +} + func TestGroup_RemoveFields(t *testing.T) { type args struct { p *Pointer diff --git a/pkg/property/pointer.go b/pkg/property/pointer.go index 658f0a82..14302f22 100644 --- a/pkg/property/pointer.go +++ b/pkg/property/pointer.go @@ -4,9 +4,9 @@ import "github.com/reearth/reearth-backend/pkg/id" // Pointer is a pointer to a field and an item in properties and schemas type Pointer struct { - schemaItem *id.PropertySchemaGroupID - item *id.PropertyItemID - field *id.PropertySchemaFieldID + schemaGroup *id.PropertySchemaGroupID + item *id.PropertyItemID + field *id.PropertySchemaFieldID } // NewPointer creates a new Pointer. @@ -15,32 +15,37 @@ func NewPointer(sg *id.PropertySchemaGroupID, i *id.PropertyItemID, f *id.Proper return nil } return &Pointer{ - schemaItem: sg.CopyRef(), - item: i.CopyRef(), - field: f.CopyRef(), + schemaGroup: sg.CopyRef(), + item: i.CopyRef(), + field: f.CopyRef(), } } -// PointField creates a new Pointer pointing the field in properties. +// PointToEverything creates a new Pointer pointing to all items and fields. +func PointToEverything() *Pointer { + return &Pointer{} +} + +// PointField creates a new Pointer pointing to the field. func PointField(sg *id.PropertySchemaGroupID, i *id.PropertyItemID, f id.PropertySchemaFieldID) *Pointer { return &Pointer{ - schemaItem: sg.CopyRef(), - item: i.CopyRef(), - field: &f, + schemaGroup: sg.CopyRef(), + item: i.CopyRef(), + field: &f, } } -// PointField creates a new Pointer pointing the field in property schemas. +// PointField creates a new Pointer pointing to the field in property schemas. func PointFieldOnly(fid id.PropertySchemaFieldID) *Pointer { return &Pointer{ field: &fid, } } -// PointItemBySchema creates a new Pointer pointing the schema item in property schemas. +// PointItemBySchema creates a new Pointer pointing to the schema item in property schemas. func PointItemBySchema(sg id.PropertySchemaGroupID) *Pointer { return &Pointer{ - schemaItem: &sg, + schemaGroup: &sg, } } @@ -54,8 +59,8 @@ func PointItem(i id.PropertyItemID) *Pointer { // PointFieldBySchemaGroup creates a new Pointer pointing to the field of the schema field in properties. func PointFieldBySchemaGroup(sg id.PropertySchemaGroupID, f id.PropertySchemaFieldID) *Pointer { return &Pointer{ - schemaItem: &sg, - field: &f, + schemaGroup: &sg, + field: &f, } } @@ -72,49 +77,33 @@ func (p *Pointer) Clone() *Pointer { return nil } return &Pointer{ - field: p.field.CopyRef(), - item: p.item.CopyRef(), - schemaItem: p.schemaItem.CopyRef(), + field: p.field.CopyRef(), + item: p.item.CopyRef(), + schemaGroup: p.schemaGroup.CopyRef(), } } func (p *Pointer) ItemBySchemaGroupAndItem() (i id.PropertySchemaGroupID, i2 id.PropertyItemID, ok bool) { - if p == nil || p.schemaItem == nil || p.item == nil { + if p == nil || p.schemaGroup == nil || p.item == nil { ok = false return } - i = *p.schemaItem + i = *p.schemaGroup i2 = *p.item ok = true return } func (p *Pointer) ItemBySchemaGroup() (i id.PropertySchemaGroupID, ok bool) { - if p == nil || p.schemaItem == nil { + if p == nil || p.schemaGroup == nil { ok = false return } - i = *p.schemaItem + i = *p.schemaGroup ok = true return } -func (p *Pointer) SchemaGroupAndItem() (i id.PropertySchemaGroupID, i2 id.PropertyItemID, ok bool) { - ok = false - if p == nil { - return - } - if p.schemaItem != nil { - i = *p.schemaItem - ok = true - } - if p.item != nil { - i2 = *p.item - ok = true - } - return -} - func (p *Pointer) Item() (i id.PropertyItemID, ok bool) { if p == nil || p.item == nil { ok = false @@ -126,15 +115,15 @@ func (p *Pointer) Item() (i id.PropertyItemID, ok bool) { } func (p *Pointer) ItemRef() *id.PropertyItemID { - if p == nil || p.item == nil { + i, ok := p.Item() + if !ok { return nil } - f := *p.item - return &f + return i.Ref() } func (p *Pointer) FieldByItem() (i id.PropertyItemID, f id.PropertySchemaFieldID, ok bool) { - if p == nil || p.item == nil || p.schemaItem != nil || p.field == nil { + if p == nil || p.item == nil || p.schemaGroup != nil || p.field == nil { ok = false return } @@ -145,11 +134,11 @@ func (p *Pointer) FieldByItem() (i id.PropertyItemID, f id.PropertySchemaFieldID } func (p *Pointer) FieldBySchemaGroup() (sg id.PropertySchemaGroupID, f id.PropertySchemaFieldID, ok bool) { - if p == nil || p.schemaItem == nil || p.item != nil || p.field == nil { + if p == nil || p.schemaGroup == nil || p.item != nil || p.field == nil { ok = false return } - sg = *p.schemaItem + sg = *p.schemaGroup f = *p.field ok = true return @@ -166,18 +155,70 @@ func (p *Pointer) Field() (f id.PropertySchemaFieldID, ok bool) { } func (p *Pointer) FieldRef() *id.PropertySchemaFieldID { - if p == nil || p.field == nil { + f, ok := p.Field() + if !ok { + return nil + } + return f.Ref() +} + +func (p *Pointer) FieldOnly() (f FieldID, ok bool) { + if p == nil || p.field == nil || p.item != nil || p.schemaGroup != nil { + ok = false + return + } + f = *p.field + ok = true + return +} + +func (p *Pointer) FieldOnlyRef() *FieldID { + f, ok := p.FieldOnly() + if !ok { + return nil + } + return f.Ref() +} + +func (p *Pointer) FieldIfItemIs(sg SchemaGroupID, i ItemID) (f FieldID, ok bool) { + if p == nil || p.field == nil || !p.TestItem(sg, i) { + ok = false + return + } + f = *p.field + ok = true + return +} + +func (p *Pointer) FieldIfItemIsRef(sg SchemaGroupID, i ItemID) *FieldID { + f, ok := p.FieldIfItemIs(sg, i) + if !ok { return nil } - f := *p.field - return &f + return f.Ref() +} + +func (p *Pointer) Test(sg SchemaGroupID, i ItemID, f FieldID) bool { + return p.TestItem(sg, i) && p.TestField(f) +} + +func (p *Pointer) TestItem(sg SchemaGroupID, i ItemID) bool { + return p.TestSchemaGroup(sg) && (p.item == nil || *p.item == i) +} + +func (p *Pointer) TestSchemaGroup(sg SchemaGroupID) bool { + return p != nil && (p.schemaGroup == nil || *p.schemaGroup == sg) +} + +func (p *Pointer) TestField(f FieldID) bool { + return p != nil && (p.field == nil || *p.field == f) } func (p *Pointer) GetAll() (sg *id.PropertySchemaGroupID, i *id.PropertyItemID, f *id.PropertySchemaFieldID) { if p == nil { return } - sg = p.schemaItem.CopyRef() + sg = p.schemaGroup.CopyRef() i = p.item.CopyRef() f = p.field.CopyRef() return diff --git a/pkg/property/pointer_test.go b/pkg/property/pointer_test.go index c1225a4e..bf7f0c4c 100644 --- a/pkg/property/pointer_test.go +++ b/pkg/property/pointer_test.go @@ -75,3 +75,242 @@ func TestPointer(t *testing.T) { _, _, ok = p.FieldBySchemaGroup() assert.False(t, ok) } + +func TestPointer_Test(t *testing.T) { + iid := NewItemID() + + type args struct { + sg SchemaGroupID + i ItemID + f FieldID + want bool + } + tests := []struct { + name string + target *Pointer + args []args + }{ + { + name: "schema group only", + target: &Pointer{schemaGroup: SchemaGroupID("xx").Ref()}, + args: []args{ + {sg: SchemaGroupID("xx"), i: iid, f: FieldID("a"), want: true}, + {sg: SchemaGroupID("xx"), i: iid, f: FieldID("b"), want: true}, + {sg: SchemaGroupID("yy"), i: iid, f: FieldID("a"), want: false}, + }, + }, + { + name: "item only", + target: &Pointer{item: iid.Ref()}, + args: []args{ + {sg: SchemaGroupID("xx"), i: iid, f: FieldID("a"), want: true}, + {sg: SchemaGroupID("yy"), i: iid, f: FieldID("a"), want: true}, + {sg: SchemaGroupID("xx"), i: iid, f: FieldID("b"), want: true}, + {sg: SchemaGroupID("xx"), i: NewItemID(), f: FieldID("a"), want: false}, + }, + }, + { + name: "schema group and item", + target: &Pointer{schemaGroup: SchemaGroupID("xx").Ref(), item: iid.Ref()}, + args: []args{ + {sg: SchemaGroupID("xx"), i: iid, f: FieldID("a"), want: true}, + {sg: SchemaGroupID("xx"), i: iid, f: FieldID("b"), want: true}, + {sg: SchemaGroupID("xx"), i: NewItemID(), f: FieldID("a"), want: false}, + {sg: SchemaGroupID("yy"), i: iid, f: FieldID("a"), want: false}, + {sg: SchemaGroupID("yy"), i: NewItemID(), f: FieldID("a"), want: false}, + }, + }, + { + name: "all", + target: &Pointer{schemaGroup: SchemaGroupID("xx").Ref(), item: iid.Ref(), field: FieldID("a").Ref()}, + args: []args{ + {sg: SchemaGroupID("xx"), i: iid, f: FieldID("a"), want: true}, + {sg: SchemaGroupID("yy"), i: iid, f: FieldID("a"), want: false}, + {sg: SchemaGroupID("xx"), i: NewItemID(), f: FieldID("a"), want: false}, + {sg: SchemaGroupID("xx"), i: iid, f: FieldID("b"), want: false}, + }, + }, + { + name: "empty", + target: &Pointer{}, + args: []args{ + {sg: SchemaGroupID("xx"), i: NewItemID(), f: FieldID("a"), want: true}, + {sg: SchemaGroupID("yy"), i: NewItemID(), f: FieldID("b"), want: true}, + {sg: SchemaGroupID("zz"), i: NewItemID(), f: FieldID("c"), want: true}, + }, + }, + { + name: "nil", + target: nil, + args: []args{ + {sg: SchemaGroupID("xx"), i: NewItemID(), f: FieldID("a"), want: false}, + {sg: SchemaGroupID("yy"), i: NewItemID(), f: FieldID("b"), want: false}, + {sg: SchemaGroupID("zz"), i: NewItemID(), f: FieldID("c"), want: false}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for i, a := range tt.args { + assert.Equal(t, a.want, tt.target.Test(a.sg, a.i, a.f), "test %d", i) + } + }) + } +} + +func TestPointer_TestItem(t *testing.T) { + iid := NewItemID() + + type args struct { + sg SchemaGroupID + i ItemID + } + tests := []struct { + name string + target *Pointer + args args + want bool + }{ + { + name: "true schema group only", + target: &Pointer{schemaGroup: SchemaGroupID("xx").Ref()}, + args: args{sg: SchemaGroupID("xx"), i: iid}, + want: true, + }, + { + name: "true item only", + target: &Pointer{item: iid.Ref()}, + args: args{sg: SchemaGroupID("xx"), i: iid}, + want: true, + }, + { + name: "true schema group and item", + target: &Pointer{schemaGroup: SchemaGroupID("xx").Ref(), item: iid.Ref()}, + args: args{sg: SchemaGroupID("xx"), i: iid}, + want: true, + }, + { + name: "true empty", + target: &Pointer{}, + args: args{sg: SchemaGroupID("xx"), i: iid}, + want: true, + }, + { + name: "false schema group only", + target: &Pointer{schemaGroup: SchemaGroupID("xx").Ref()}, + args: args{sg: SchemaGroupID("yy"), i: iid}, + want: false, + }, + { + name: "false item only", + target: &Pointer{item: iid.Ref()}, + args: args{sg: SchemaGroupID("xx"), i: NewItemID()}, + want: false, + }, + { + name: "false schema group and item", + target: &Pointer{schemaGroup: SchemaGroupID("xx").Ref(), item: iid.Ref()}, + args: args{sg: SchemaGroupID("xx"), i: NewItemID()}, + want: false, + }, + { + name: "false nil", + target: nil, + args: args{sg: SchemaGroupID("xx"), i: iid}, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.TestItem(tt.args.sg, tt.args.i)) + }) + } +} + +func TestPointer_TestSchemaGroup(t *testing.T) { + type args struct { + sg SchemaGroupID + } + tests := []struct { + name string + target *Pointer + args args + want bool + }{ + { + name: "true", + target: &Pointer{schemaGroup: SchemaGroupID("xx").Ref()}, + args: args{sg: SchemaGroupID("xx")}, + want: true, + }, + { + name: "false", + target: &Pointer{schemaGroup: SchemaGroupID("xx").Ref()}, + args: args{sg: SchemaGroupID("yy")}, + want: false, + }, + { + name: "empty", + target: &Pointer{}, + args: args{sg: SchemaGroupID("xx")}, + want: true, + }, + { + name: "nil", + target: nil, + args: args{sg: SchemaGroupID("xx")}, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.TestSchemaGroup(tt.args.sg)) + }) + } +} + +func TestPointer_TestField(t *testing.T) { + type args struct { + f FieldID + } + tests := []struct { + name string + target *Pointer + args args + want bool + }{ + { + name: "true", + target: &Pointer{field: FieldID("xx").Ref()}, + args: args{f: FieldID("xx")}, + want: true, + }, + { + name: "false", + target: &Pointer{field: FieldID("xx").Ref()}, + args: args{f: FieldID("yy")}, + want: false, + }, + { + name: "empty", + target: &Pointer{}, + args: args{f: FieldID("xx")}, + want: true, + }, + { + name: "nil", + target: nil, + args: args{f: FieldID("xx")}, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.TestField(tt.args.f)) + }) + } +} diff --git a/pkg/property/property.go b/pkg/property/property.go index 65913c43..da36224c 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -226,8 +226,8 @@ func (p *Property) Datasets() []id.DatasetID { if p == nil { return nil } - res := []id.DatasetID{} + res := []id.DatasetID{} for _, f := range p.items { res = append(res, f.Datasets()...) } @@ -236,17 +236,15 @@ func (p *Property) Datasets() []id.DatasetID { } func (p *Property) RemoveItem(ptr *Pointer) { - if p == nil { - return - } - sgid, iid, ok := ptr.SchemaGroupAndItem() - if !ok { + if p == nil || ptr == nil { return } - for i, item := range p.items { - if item.ID() == iid || item.SchemaGroup() == sgid { + + for i := 0; i < len(p.items); i++ { + item := p.items[i] + if ptr.TestItem(item.SchemaGroup(), item.ID()) { p.items = append(p.items[:i], p.items[i+1:]...) - return + i-- } } } @@ -513,3 +511,28 @@ func (p *Property) ValidateSchema(ps *Schema) error { return nil } + +// MoveFields moves fields between items. Only fields in Groups can be moved to another Group, fields in GroupLists will simply be deleted. +func (p *Property) MoveFields(f FieldID, from, to SchemaGroupID) { + if p == nil { + return + } + + fromItem := p.ItemBySchema(from) + if fromItem == nil { + return + } + + fields := p.Fields(PointFieldBySchemaGroup(from, f)) + if len(fields) == 0 { + return + } + + toGroup := p.GroupBySchema(to) + for _, f := range fields { + fromItem.RemoveFields(PointFieldOnly(f.Field())) + if toGroup != nil { + toGroup.AddFields(f) + } + } +} diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index 9cc311b9..f34fdce8 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -406,3 +406,129 @@ func TestProperty_RemoveFields(t *testing.T) { }) } } + +func TestProperty_MoveFields(t *testing.T) { + sg1 := SchemaGroupID("aaa") + sg2 := SchemaGroupID("bbb") + sg3 := SchemaGroupID("ccc") + sg4 := SchemaGroupID("ddd") + + f1 := NewFieldUnsafe().FieldUnsafe(FieldID("x")).ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("aaa"))).Build() + f2 := NewFieldUnsafe().FieldUnsafe(FieldID("y")).ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("bbb"))).Build() + p := New().NewID().Scene(id.NewSceneID()).Schema(testSchema1.ID()).Items([]Item{ + NewGroup().NewID().Schema(testSchema1.ID(), sg1).Fields([]*Field{ + f1, + }).MustBuild(), + NewGroup().NewID().Schema(testSchema1.ID(), sg2).Fields([]*Field{ + // empty + }).MustBuild(), + NewGroupList().NewID().Schema(testSchema1.ID(), sg3).Groups([]*Group{ + NewGroup().NewID().Schema(testSchema1.ID(), sg3).Fields([]*Field{ + f2, + }).MustBuild(), + }).MustBuild(), + NewGroupList().NewID().Schema(testSchema1.ID(), sg4).Groups([]*Group{ + NewGroup().NewID().Schema(testSchema1.ID(), sg4).Fields([]*Field{ + // empty + }).MustBuild(), + }).MustBuild(), + }).MustBuild() + + type args struct { + f FieldID + from SchemaGroupID + to SchemaGroupID + } + tests := []struct { + name string + target *Property + args args + fromFields []*Field + toFields []*Field + }{ + { + name: "group->group", + target: p.Clone(), + args: args{ + f: f1.Field(), + from: sg1, + to: sg2, + }, + fromFields: []*Field{}, // deleted + toFields: []*Field{f1}, // added + }, + { + name: "group->group failed", + target: p.Clone(), + args: args{ + f: f2.Field(), + from: sg1, + to: sg2, + }, + fromFields: []*Field{f1}, // not deleted + toFields: []*Field{}, // not added + }, + { + name: "group list->group list", + target: p.Clone(), + args: args{ + f: f2.Field(), + from: sg3, + to: sg4, + }, + fromFields: []*Field{}, // deleted + toFields: []*Field{}, // not added + }, + { + name: "group->group list", + target: testProperty1.Clone(), + args: args{ + f: f1.Field(), + from: sg1, + to: sg4, + }, + fromFields: []*Field{}, // deleted + toFields: []*Field{}, // not added + }, + { + name: "group list->group", + target: testProperty1.Clone(), + args: args{ + f: f2.Field(), + from: sg3, + to: sg2, + }, + fromFields: []*Field{}, // deleted + toFields: []*Field{}, // not added + }, + { + name: "empty", + target: &Property{}, + args: args{ + f: f1.Field(), + from: sg1, + to: sg2, + }, + fromFields: nil, + toFields: nil, + }, + { + name: "nil", + args: args{ + f: f1.Field(), + from: sg1, + to: sg2, + }, + fromFields: nil, + toFields: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.target.MoveFields(tt.args.f, tt.args.from, tt.args.to) + assert.Equal(t, tt.fromFields, tt.target.Fields(PointItemBySchema(tt.args.from))) + assert.Equal(t, tt.toFields, tt.target.Fields(PointItemBySchema(tt.args.to))) + }) + } +} From 496244925b41e83cd3ecf95dd604397ea88e2066 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Fri, 10 Dec 2021 19:33:04 +0900 Subject: [PATCH 18/55] remove property.FieldUnsafeBuilder --- .../infrastructure/mongo/mongodoc/property.go | 8 +- pkg/property/builder_test.go | 36 +- pkg/property/field.go | 12 +- pkg/property/field_builder.go | 56 +-- pkg/property/field_builder_test.go | 220 +---------- pkg/property/field_test.go | 169 +++++++-- pkg/property/group.go | 2 +- pkg/property/group_builder_test.go | 16 +- pkg/property/group_list.go | 10 +- pkg/property/group_list_test.go | 348 +++++++++--------- pkg/property/group_test.go | 112 +++--- pkg/property/initializer.go | 2 +- pkg/property/initializer_test.go | 12 +- pkg/property/item_test.go | 6 +- pkg/property/merged_test.go | 16 +- pkg/property/property_test.go | 44 ++- pkg/scene/builder/builder_test.go | 106 +++--- 17 files changed, 537 insertions(+), 638 deletions(-) diff --git a/internal/infrastructure/mongo/mongodoc/property.go b/internal/infrastructure/mongo/mongodoc/property.go index 28f28939..5975c346 100644 --- a/internal/infrastructure/mongo/mongodoc/property.go +++ b/internal/infrastructure/mongo/mongodoc/property.go @@ -220,10 +220,10 @@ func toModelPropertyField(f *PropertyFieldDocument) *property.Field { } vt := property.ValueType(f.Type) - field := property.NewFieldUnsafe(). - FieldUnsafe(id.PropertySchemaFieldID(f.Field)). - ValueUnsafe(property.NewOptionalValue(vt, toModelPropertyValue(f.Value, f.Type))). - LinksUnsafe(flinks). + field := property.NewField(). + Field(id.PropertySchemaFieldID(f.Field)). + Value(property.NewOptionalValue(vt, toModelPropertyValue(f.Value, f.Type))). + Link(flinks). Build() return field diff --git a/pkg/property/builder_test.go b/pkg/property/builder_test.go index 55171030..b1f16cc7 100644 --- a/pkg/property/builder_test.go +++ b/pkg/property/builder_test.go @@ -55,24 +55,24 @@ func TestBuilder_Items(t *testing.T) { Input: []Item{ NewGroup().ID(iid).Schema(propertySchemaID, propertySchemaGroup1ID). Fields([]*Field{ - NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). + NewField(). + Field(propertySchemaField1ID). + Value(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). Build(), }).MustBuild(), NewGroup().ID(iid).Schema(propertySchemaID, propertySchemaGroup1ID). Fields([]*Field{ - NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). + NewField(). + Field(propertySchemaField1ID). + Value(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). Build(), }).MustBuild(), }, Expected: []Item{NewGroup().ID(iid).Schema(propertySchemaID, propertySchemaGroup1ID). Fields([]*Field{ - NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). + NewField(). + Field(propertySchemaField1ID). + Value(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). Build(), }).MustBuild()}, }, @@ -122,9 +122,9 @@ func TestBuilder_Build(t *testing.T) { Items: []Item{ NewGroup().ID(iid).Schema(scid, propertySchemaGroup1ID). Fields([]*Field{ - NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). + NewField(). + Field(propertySchemaField1ID). + Value(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). Build(), }).MustBuild()}, Expected: struct { @@ -139,9 +139,9 @@ func TestBuilder_Build(t *testing.T) { Items: []Item{ NewGroup().ID(iid).Schema(scid, propertySchemaGroup1ID). Fields([]*Field{ - NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). + NewField(). + Field(propertySchemaField1ID). + Value(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). Build(), }).MustBuild()}, }, @@ -173,9 +173,9 @@ func TestBuilder_Build(t *testing.T) { Items: []Item{ NewGroup().ID(iid).Schema(id.MustPropertySchemaID("zzz~1.1.1/aa"), propertySchemaGroup1ID). Fields([]*Field{ - NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). + NewField(). + Field(propertySchemaField1ID). + Value(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). Build(), }).MustBuild()}, Err: ErrInvalidItem, diff --git a/pkg/property/field.go b/pkg/property/field.go index d7e9a8a3..c1373242 100644 --- a/pkg/property/field.go +++ b/pkg/property/field.go @@ -22,6 +22,9 @@ type Field struct { } func (p *Field) Clone() *Field { + if p == nil { + return nil + } return &Field{ field: p.field, links: p.links.Clone(), @@ -30,6 +33,9 @@ func (p *Field) Clone() *Field { } func (p *Field) Field() id.PropertySchemaFieldID { + if p == nil { + return FieldID("") + } return p.field } @@ -55,6 +61,10 @@ func (p *Field) Value() *Value { } func (p *Field) ActualValue(ds *dataset.Dataset) *ValueAndDatasetValue { + if p == nil { + return nil + } + var dv *dataset.Value if p.links != nil { if l := p.links.Last(); !l.IsEmpty() { @@ -75,8 +85,8 @@ func (p *Field) Datasets() []id.DatasetID { if p == nil { return nil } - res := []id.DatasetID{} + res := []id.DatasetID{} if p.Links().IsLinkedFully() { dsid := p.Links().Last().Dataset() if dsid != nil { diff --git a/pkg/property/field_builder.go b/pkg/property/field_builder.go index 53de74e5..ea7d3c07 100644 --- a/pkg/property/field_builder.go +++ b/pkg/property/field_builder.go @@ -2,7 +2,6 @@ package property import ( "github.com/reearth/reearth-backend/pkg/dataset" - "github.com/reearth/reearth-backend/pkg/id" ) type FieldBuilder struct { @@ -14,37 +13,29 @@ type FieldUnsafeBuilder struct { p *Field } -func NewField(p *SchemaField) *FieldBuilder { - b := &FieldBuilder{ +func NewField() *FieldBuilder { + return &FieldBuilder{ p: &Field{}, } - return b.schemaField(p) } -func (b *FieldBuilder) Build() (*Field, error) { - if b.p.field == id.PropertySchemaFieldID("") { - return nil, id.ErrInvalidID +func (b *FieldBuilder) Build() *Field { + if b.p.field == FieldID("") || b.p.v == nil { + return nil } - if b.psf != nil && !b.psf.Validate(b.p.v) { - return nil, ErrInvalidPropertyValue - } - return b.p, nil + return b.p } func (b *FieldBuilder) MustBuild() *Field { - p, err := b.Build() - if err != nil { - panic(err) + p := b.Build() + if p == nil { + panic("invalid field") } return p } -func (b *FieldBuilder) schemaField(p *SchemaField) *FieldBuilder { - if p != nil { - b.psf = p - b.p.field = p.ID() - b.p.v = NewOptionalValue(p.Type(), p.DefaultValue().Clone()) - } +func (b *FieldBuilder) Field(f FieldID) *FieldBuilder { + b.p.field = f return b } @@ -57,28 +48,3 @@ func (b *FieldBuilder) Link(l *dataset.GraphPointer) *FieldBuilder { b.p.links = l.Clone() return b } - -func NewFieldUnsafe() *FieldUnsafeBuilder { - return &FieldUnsafeBuilder{ - p: &Field{}, - } -} - -func (b *FieldUnsafeBuilder) Build() *Field { - return b.p -} - -func (b *FieldUnsafeBuilder) FieldUnsafe(f id.PropertySchemaFieldID) *FieldUnsafeBuilder { - b.p.field = f - return b -} - -func (b *FieldUnsafeBuilder) ValueUnsafe(v *OptionalValue) *FieldUnsafeBuilder { - b.p.v = v.Clone() - return b -} - -func (b *FieldUnsafeBuilder) LinksUnsafe(l *dataset.GraphPointer) *FieldUnsafeBuilder { - b.p.links = l.Clone() - return b -} diff --git a/pkg/property/field_builder_test.go b/pkg/property/field_builder_test.go index d48c0ea6..505572eb 100644 --- a/pkg/property/field_builder_test.go +++ b/pkg/property/field_builder_test.go @@ -1,7 +1,6 @@ package property import ( - "errors" "testing" "github.com/reearth/reearth-backend/pkg/dataset" @@ -10,224 +9,33 @@ import ( ) func TestFieldBuilder_Value(t *testing.T) { - p := NewSchemaField().ID("A").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") - b := NewField(p).Value(OptionalValueFrom(v)).MustBuild() + b := NewField().Field("a").Value(OptionalValueFrom(v)).Build() assert.Equal(t, v, b.Value()) } func TestFieldBuilder_Link(t *testing.T) { - p := NewSchemaField().ID("A").Type(ValueTypeString).MustBuild() - l := dataset.PointAt(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) - ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) - b := NewField(p).Link(ls).MustBuild() - assert.Equal(t, ls, b.Links()) -} + l := dataset.NewGraphPointer([]*dataset.Pointer{ + dataset.PointAt(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()), + }) -func TestFieldBuilder_Build(t *testing.T) { - l := dataset.PointAt(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) - testCases := []struct { - Name string - Links *dataset.GraphPointer - Value *Value - SF *SchemaField - Expected struct { - PType ValueType - Links *dataset.GraphPointer - Value *Value - } - Err error + tests := []struct { + Name string + Links *dataset.GraphPointer }{ - { - Name: "fail invalid property id", - Expected: struct { - PType ValueType - Links *dataset.GraphPointer - Value *Value - }{}, - Err: id.ErrInvalidID, - }, - { - Name: "fail invalid property type", - SF: NewSchemaField().ID("A").Type(ValueTypeBool).MustBuild(), - Value: ValueTypeString.ValueFrom("vvv"), - Expected: struct { - PType ValueType - Links *dataset.GraphPointer - Value *Value - }{}, - Err: ErrInvalidPropertyType, - }, { Name: "success", - SF: NewSchemaField().ID("A").Type(ValueTypeString).MustBuild(), - Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), - Value: ValueTypeString.ValueFrom("vvv"), - Expected: struct { - PType ValueType - Links *dataset.GraphPointer - Value *Value - }{ - PType: ValueTypeString, - Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), - Value: ValueTypeString.ValueFrom("vvv"), - }, - Err: nil, + Links: l, }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - res, err := NewField(tc.SF).Value(OptionalValueFrom(tc.Value)).Link(tc.Links).Build() - if err == nil { - assert.Equal(tt, tc.Expected.Links, res.Links()) - assert.Equal(tt, tc.Expected.PType, res.Type()) - assert.Equal(tt, tc.Expected.Value, res.Value()) - } else { - assert.True(tt, errors.As(tc.Err, &err)) - } - }) - } -} -func TestFieldBuilder_MustBuild(t *testing.T) { - l := dataset.PointAt(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) - testCases := []struct { - Name string - Fails bool - Links *dataset.GraphPointer - Value *Value - SF *SchemaField - Expected struct { - PType ValueType - Links *dataset.GraphPointer - Value *Value - } - }{ - { - Name: "fail invalid property id", - Fails: true, - Expected: struct { - PType ValueType - Links *dataset.GraphPointer - Value *Value - }{}, - }, - { - Name: "fail invalid property type", - SF: NewSchemaField().ID("A").Type(ValueTypeBool).MustBuild(), - Value: ValueTypeString.ValueFrom("vvv"), - Fails: true, - Expected: struct { - PType ValueType - Links *dataset.GraphPointer - Value *Value - }{}, - }, - { - Name: "success", - SF: NewSchemaField().ID("A").Type(ValueTypeString).MustBuild(), - Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), - Value: ValueTypeString.ValueFrom("vvv"), - Expected: struct { - PType ValueType - Links *dataset.GraphPointer - Value *Value - }{ - PType: ValueTypeString, - Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), - Value: ValueTypeString.ValueFrom("vvv"), - }, - }, - } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - var res *Field - if tc.Fails { - defer func() { - if r := recover(); r != nil { - assert.Nil(tt, res) - } - }() - res = NewField(tc.SF).Value(OptionalValueFrom(tc.Value)).Link(tc.Links).MustBuild() - } else { - res = NewField(tc.SF).Value(OptionalValueFrom(tc.Value)).Link(tc.Links).MustBuild() - assert.Equal(tt, tc.Expected.Links, res.Links()) - assert.Equal(tt, tc.Expected.PType, res.Type()) - assert.Equal(tt, tc.Expected.Value, res.Value()) - } - }) - } -} - -func TestNewFieldUnsafe(t *testing.T) { - p := NewFieldUnsafe().Build() - assert.NotNil(t, p) -} + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() -func TestFieldUnsafeBuilder_Build(t *testing.T) { - l := dataset.PointAt(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) - testCases := []struct { - Name string - Links *dataset.GraphPointer - Value *Value - Type ValueType - Field id.PropertySchemaFieldID - Expected struct { - PType ValueType - Field id.PropertySchemaFieldID - Links *dataset.GraphPointer - Value *Value - } - }{ - { - Name: "success", - Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), - Value: ValueTypeString.ValueFrom("vvv"), - Type: ValueTypeString, - Field: "a", - Expected: struct { - PType ValueType - Field id.PropertySchemaFieldID - Links *dataset.GraphPointer - Value *Value - }{ - PType: ValueTypeString, - Field: "a", - Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), - Value: ValueTypeString.ValueFrom("vvv"), - }, - }, - { - Name: "nil value", - Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), - Value: nil, - Type: ValueTypeString, - Field: "a", - Expected: struct { - PType ValueType - Field id.PropertySchemaFieldID - Links *dataset.GraphPointer - Value *Value - }{ - PType: ValueTypeString, - Field: "a", - Links: dataset.NewGraphPointer([]*dataset.Pointer{l}), - Value: nil, - }, - }, - } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - res := NewFieldUnsafe().ValueUnsafe(NewOptionalValue(tc.Type, tc.Value)).LinksUnsafe(tc.Links).FieldUnsafe(tc.Field).Build() - assert.Equal(tt, tc.Expected.Links, res.Links()) - assert.Equal(tt, tc.Expected.PType, res.Type()) - assert.Equal(tt, tc.Expected.Value, res.Value()) + res := NewField().Field(FieldID("a")).Value(NewOptionalValue(ValueTypeBool, nil)).Link(tt.Links).Build() + assert.Equal(t, l, res.Links()) }) } } diff --git a/pkg/property/field_test.go b/pkg/property/field_test.go index e0705e5d..71c091b2 100644 --- a/pkg/property/field_test.go +++ b/pkg/property/field_test.go @@ -9,19 +9,18 @@ import ( ) var ( - testField1 = NewField(testSchemaField1).Value(OptionalValueFrom(ValueTypeString.ValueFrom("aaa"))).MustBuild() - testField2 = NewField(testSchemaField3).Value(NewOptionalValue(ValueTypeLatLng, nil)).MustBuild() + testField1 = NewField().Field(testSchemaField1.ID()).Value(OptionalValueFrom(ValueTypeString.ValueFrom("aaa"))).MustBuild() + testField2 = NewField().Field(testSchemaField3.ID()).Value(NewOptionalValue(ValueTypeLatLng, nil)).MustBuild() ) func TestField_ActualValue(t *testing.T) { - p := NewSchemaField().ID("A").Type(ValueTypeString).MustBuild() dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() dssfid := id.NewDatasetSchemaFieldID() l := dataset.PointAt(dsid, dssid, dssfid) ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) - testCases := []struct { + tests := []struct { Name string Field *Field DS *dataset.Dataset @@ -29,17 +28,17 @@ func TestField_ActualValue(t *testing.T) { }{ { Name: "nil links", - Field: NewField(p).Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).MustBuild(), + Field: NewField().Field("a").Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Build(), Expected: NewValueAndDatasetValue(ValueTypeString, nil, ValueTypeString.ValueFrom("vvv")), }, { Name: "empty links", - Field: NewField(p).Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Link(&dataset.GraphPointer{}).MustBuild(), + Field: NewField().Field("a").Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Link(&dataset.GraphPointer{}).Build(), Expected: NewValueAndDatasetValue(ValueTypeString, nil, ValueTypeString.ValueFrom("vvv")), }, { Name: "dataset value", - Field: NewField(p).Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Link(ls).MustBuild(), + Field: NewField().Field("a").Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Link(ls).Build(), DS: dataset.New(). ID(dsid).Schema(dssid). Fields([]*dataset.Field{ @@ -50,38 +49,37 @@ func TestField_ActualValue(t *testing.T) { }, { Name: "dataset value missing", - Field: NewField(p).Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Link(ls).MustBuild(), + Field: NewField().Field("a").Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Link(ls).Build(), DS: dataset.New().ID(dsid).Schema(dssid).MustBuild(), Expected: NewValueAndDatasetValue(ValueTypeString, nil, ValueTypeString.ValueFrom("vvv")), }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - res := tc.Field.ActualValue(tc.DS) - assert.Equal(tt, tc.Expected, res) + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + res := tt.Field.ActualValue(tt.DS) + assert.Equal(t, tt.Expected, res) }) } } func TestField_Datasets(t *testing.T) { - p := NewSchemaField().ID("A").Type(ValueTypeString).MustBuild() dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() dssfid := id.NewDatasetSchemaFieldID() l := dataset.PointAt(dsid, dssid, dssfid) ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) - testCases := []struct { + tests := []struct { Name string Field *Field Expected []id.DatasetID }{ { Name: "list of one datasets", - Field: NewField(p).Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Link(ls).MustBuild(), + Field: NewField().Field("a").Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Link(ls).Build(), Expected: []id.DatasetID{dsid}, }, { @@ -90,42 +88,135 @@ func TestField_Datasets(t *testing.T) { }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - res := tc.Field.Datasets() - assert.Equal(tt, tc.Expected, res) + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + res := tt.Field.Datasets() + assert.Equal(t, tt.Expected, res) }) } } func TestField_Clone(t *testing.T) { - p := NewSchemaField().ID("A").Type(ValueTypeString).MustBuild() l := dataset.PointAt(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) - b := NewField(p).Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Link(ls).MustBuild() - r := b.Clone() - assert.Equal(t, b, r) + b := NewField().Field("a").Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Link(ls).Build() + + tests := []struct { + name string + target *Field + want *Field + }{ + { + name: "ok", + target: b, + want: b, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + r := b.Clone() + assert.Equal(t, b, r) + if tt.want != nil { + assert.NotSame(t, b, r) + } + }) + } } -func TestField(t *testing.T) { +func TestField_IsEmpty(t *testing.T) { + tests := []struct { + name string + target *Field + want bool + }{ + { + name: "empty", + target: &Field{}, + want: true, + }, + { + name: "empty value", + target: NewField().Field("a").Value(NewOptionalValue(ValueTypeString, nil)).Build(), + want: true, + }, + { + name: "not empty", + target: NewField().Field("a").Value(OptionalValueFrom(ValueTypeString.ValueFrom("x"))).Build(), + want: false, + }, + { + name: "nil", + target: nil, + want: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.IsEmpty()) + }) + } +} + +func TestField_Link(t *testing.T) { did := id.NewDatasetID() dsid := id.NewDatasetSchemaID() - p := NewSchemaField().ID("A").Type(ValueTypeString).MustBuild() - b := NewField(p).MustBuild() - assert.True(t, b.IsEmpty()) - l := dataset.PointAt(did, dsid, id.NewDatasetSchemaFieldID()) - ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) - b.Link(ls) - assert.True(t, b.IsDatasetLinked(dsid, did)) - b.Unlink() - assert.Nil(t, b.Links()) + dfid := id.NewDatasetSchemaFieldID() + l := dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(did, dsid, dfid)}) + + tests := []struct { + name string + target *Field + args *dataset.GraphPointer + }{ + { + name: "link", + target: testField1.Clone(), + args: l, + }, + { + name: "unlink", + target: NewField().Field("a").Value(NewOptionalValue(ValueTypeString, nil)).Link(l).Build(), + args: nil, + }, + { + name: "empty", + target: &Field{}, + args: nil, + }, + { + name: "nil", + target: nil, + args: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + tt.target.Link(tt.args) + if tt.target != nil { + assert.Equal(t, tt.args, tt.target.links) + } + }) + } } func TestField_Update(t *testing.T) { - p := NewSchemaField().ID("A").Type(ValueTypeString).MustBuild() - b := NewField(p).Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).MustBuild() + b := NewField().Field("a").Value(OptionalValueFrom(ValueTypeString.ValueFrom("vvv"))).Build() v := ValueTypeString.ValueFrom("xxx") b.UpdateUnsafe(v) assert.Equal(t, v, b.Value()) diff --git a/pkg/property/group.go b/pkg/property/group.go index 7ee71743..c604f6f6 100644 --- a/pkg/property/group.go +++ b/pkg/property/group.go @@ -148,7 +148,7 @@ func (g *Group) GetOrCreateField(ps *Schema, fid id.PropertySchemaFieldID) (*Fie } // if the field does not exist, create it here - field, _ = NewField(psf).Build() + field = NewField().Field(fid).Value(NewOptionalValue(psf.Type(), nil)).Build() if field == nil { return nil, false } diff --git a/pkg/property/group_builder_test.go b/pkg/property/group_builder_test.go index 79d00766..091ffc2b 100644 --- a/pkg/property/group_builder_test.go +++ b/pkg/property/group_builder_test.go @@ -11,10 +11,10 @@ import ( func TestGroupBuilder_Build(t *testing.T) { iid := id.NewPropertyItemID() sid := id.MustPropertySchemaID("xx~1.0.0/aa") - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") - f := NewField(sf).Value(OptionalValueFrom(v)).MustBuild() - testCases := []struct { + f := NewField().Field("a").Value(OptionalValueFrom(v)).Build() + + tests := []struct { Name string Id id.PropertyItemID Schema id.PropertySchemaID @@ -53,7 +53,7 @@ func TestGroupBuilder_Build(t *testing.T) { }, } - for _, tc := range testCases { + for _, tc := range tests { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() @@ -73,10 +73,10 @@ func TestGroupBuilder_Build(t *testing.T) { func TestGroupBuilder_MustBuild(t *testing.T) { iid := id.NewPropertyItemID() sid := id.MustPropertySchemaID("xx~1.0.0/aa") - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") - f := NewField(sf).Value(OptionalValueFrom(v)).MustBuild() - testCases := []struct { + f := NewField().Field("a").Value(OptionalValueFrom(v)).Build() + + tests := []struct { Name string Fail bool Id id.PropertyItemID @@ -114,7 +114,7 @@ func TestGroupBuilder_MustBuild(t *testing.T) { }, } - for _, tc := range testCases { + for _, tc := range tests { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() diff --git a/pkg/property/group_list.go b/pkg/property/group_list.go index 79c35b6e..ad4f17d0 100644 --- a/pkg/property/group_list.go +++ b/pkg/property/group_list.go @@ -389,15 +389,13 @@ func (g *GroupList) RemoveFields(ptr *Pointer) { return } - if i, ok := ptr.Item(); ok { - g.Group(i).RemoveFields(ptr) + if i, ok := ptr.Item(); ok && g.ID() != i { + g.GroupByPointer(ptr).RemoveFields(ptr) return } - if psg, pf, ok := ptr.FieldBySchemaGroup(); ok && psg == g.SchemaGroup() { - for _, g := range g.groups { - g.RemoveField(pf) - } + if i, ok := ptr.ItemBySchemaGroup(); ok && g.SchemaGroup() != i { + g.GroupByPointer(ptr).RemoveFields(ptr) return } diff --git a/pkg/property/group_list_test.go b/pkg/property/group_list_test.go index 7378c127..d8fdefdb 100644 --- a/pkg/property/group_list_test.go +++ b/pkg/property/group_list_test.go @@ -14,11 +14,10 @@ var ( func TestGroupList_HasLinkedField(t *testing.T) { pid := id.NewPropertyItemID() - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() - f := NewField(sf).Value(OptionalValueFrom(v)).Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID())})).MustBuild() + f := NewField().Field("a").Value(OptionalValueFrom(v)).Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID())})).Build() groups := []*Group{NewGroup().ID(pid).Fields([]*Field{f}).MustBuild()} groups2 := []*Group{NewGroup().ID(pid).MustBuild()} testCases := []struct { @@ -52,16 +51,16 @@ func TestGroupList_HasLinkedField(t *testing.T) { func TestGroupList_Datasets(t *testing.T) { pid := id.NewPropertyItemID() - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() - f := NewField(sf).Value(OptionalValueFrom(v)).Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID())})).MustBuild() + f := NewField().Field("a").Value(OptionalValueFrom(v)).Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID())})).Build() groups := []*Group{NewGroup().ID(pid).Fields([]*Field{f}).MustBuild()} groups2 := []*Group{NewGroup().ID(pid).MustBuild()} - testCases := []struct { + + tests := []struct { Name string - GL *GroupList + Target *GroupList Expected []id.DatasetID }{ { @@ -69,36 +68,37 @@ func TestGroupList_Datasets(t *testing.T) { }, { Name: "one dataset", - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups).MustBuild(), Expected: []id.DatasetID{dsid}, }, { Name: "empty list", - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups2).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups2).MustBuild(), Expected: []id.DatasetID{}, }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - assert.Equal(tt, tc.Expected, tc.GL.Datasets()) + + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.Expected, tt.Target.Datasets()) }) } } func TestGroupList_FieldsByLinkedDataset(t *testing.T) { pid := id.NewPropertyItemID() - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() - f := NewField(sf).Value(OptionalValueFrom(v)).Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID())})).MustBuild() + f := NewField().Field("a").Value(OptionalValueFrom(v)).Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID())})).Build() groups := []*Group{NewGroup().ID(pid).Fields([]*Field{f}).MustBuild()} groups2 := []*Group{NewGroup().ID(pid).MustBuild()} - testCases := []struct { + + tests := []struct { Name string - GL *GroupList + Target *GroupList Expected []*Field }{ { @@ -106,35 +106,36 @@ func TestGroupList_FieldsByLinkedDataset(t *testing.T) { }, { Name: "one field list", - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups).MustBuild(), Expected: []*Field{f}, }, { Name: "empty list", - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups2).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups2).MustBuild(), Expected: []*Field{}, }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - assert.Equal(tt, tc.Expected, tc.GL.FieldsByLinkedDataset(dssid, dsid)) + + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.Expected, tt.Target.FieldsByLinkedDataset(dssid, dsid)) }) } } func TestGroupList_IsEmpty(t *testing.T) { pid := id.NewPropertyItemID() - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() - f := NewField(sf).Value(OptionalValueFrom(v)).Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID())})).MustBuild() + f := NewField().Field("a").Value(OptionalValueFrom(v)).Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID())})).Build() groups := []*Group{NewGroup().ID(pid).Fields([]*Field{f}).MustBuild()} - testCases := []struct { + + tests := []struct { Name string - GL *GroupList + Target *GroupList Expected bool }{ { @@ -142,35 +143,35 @@ func TestGroupList_IsEmpty(t *testing.T) { }, { Name: "is empty", - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").MustBuild(), Expected: true, }, { Name: "is not empty", - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups).MustBuild(), Expected: false, }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - assert.Equal(tt, tc.Expected, tc.GL.IsEmpty()) + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.Expected, tt.Target.IsEmpty()) }) } } func TestGroupList_Prune(t *testing.T) { - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") - f := NewField(sf).Value(OptionalValueFrom(v)).MustBuild() - f2 := NewField(sf).MustBuild() + f := NewField().Field("a").Value(OptionalValueFrom(v)).Build() + f2 := NewField().Field("a").Build() pid := id.NewPropertyItemID() groups := []*Group{NewGroup().ID(pid).Fields([]*Field{f, f2}).MustBuild()} pruned := []*Group{NewGroup().ID(pid).Fields([]*Field{f}).MustBuild()} - testCases := []struct { + + tests := []struct { Name string - GL *GroupList + Target *GroupList Expected []*Group }{ { @@ -178,16 +179,17 @@ func TestGroupList_Prune(t *testing.T) { }, { Name: "pruned list", - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups).MustBuild(), Expected: pruned, }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - tc.GL.Prune() - assert.Equal(tt, tc.Expected, tc.GL.Groups()) + + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + tt.Target.Prune() + assert.Equal(t, tt.Expected, tt.Target.Groups()) }) } } @@ -195,10 +197,11 @@ func TestGroupList_Prune(t *testing.T) { func TestGroupList_Group(t *testing.T) { pid := id.NewPropertyItemID() g := NewGroup().ID(pid).MustBuild() - testCases := []struct { + + tests := []struct { Name string Input id.PropertyItemID - GL *GroupList + Target *GroupList Expected *Group }{ { @@ -207,21 +210,22 @@ func TestGroupList_Group(t *testing.T) { { Name: "found", Input: pid, - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g}).MustBuild(), Expected: g, }, { Name: "not found", Input: id.NewPropertyItemID(), - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g}).MustBuild(), Expected: nil, }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - assert.Equal(tt, tc.Expected, tc.GL.Group(tc.Input)) + + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.Expected, tt.Target.Group(tt.Input)) }) } } @@ -281,37 +285,38 @@ func TestGroupList_GroupAt(t *testing.T) { g4 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() gl := NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild() - testCases := []struct { + tests := []struct { Name string Index int - GL *GroupList + Target *GroupList Expected *Group }{ { Name: "nil group list", }, { - Name: "index < 0", - Index: -1, - GL: gl, + Name: "index < 0", + Index: -1, + Target: gl, }, { - Name: "index > len(g)-1", - Index: 4, - GL: gl, + Name: "index > len(g)-1", + Index: 4, + Target: gl, }, { Name: "found", Index: 2, - GL: gl, + Target: gl, Expected: g3, }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - assert.Equal(tt, tc.Expected, tc.GL.GroupAt(tc.Index)) + + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.Expected, tt.Target.GroupAt(tt.Index)) }) } } @@ -321,10 +326,11 @@ func TestGroupList_Has(t *testing.T) { g2 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g3 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g4 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() - testCases := []struct { + + tests := []struct { Name string Input id.PropertyItemID - GL *GroupList + Target *GroupList Expected bool }{ { @@ -333,21 +339,22 @@ func TestGroupList_Has(t *testing.T) { { Name: "found", Input: g2.ID(), - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: true, }, { Name: "not found", Input: g3.ID(), - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g4}).MustBuild(), Expected: false, }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - assert.Equal(tt, tc.Expected, tc.GL.Has(tc.Input)) + + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.Expected, tt.Target.Has(tt.Input)) }) } } @@ -357,9 +364,10 @@ func TestGroupList_Count(t *testing.T) { g2 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g3 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g4 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() - testCases := []struct { + + tests := []struct { Name string - GL *GroupList + Target *GroupList Expected int }{ { @@ -367,15 +375,16 @@ func TestGroupList_Count(t *testing.T) { }, { Name: "not found", - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: 4, }, } - for _, tc := range testCases { + + for _, tc := range tests { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() - assert.Equal(tt, tc.Expected, tc.GL.Count()) + assert.Equal(tt, tc.Expected, tc.Target.Count()) }) } } @@ -385,7 +394,8 @@ func TestGroupList_Add(t *testing.T) { g2 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g3 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g4 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() - testCases := []struct { + + tests := []struct { Name string GL *GroupList Gr *Group @@ -426,12 +436,12 @@ func TestGroupList_Add(t *testing.T) { }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - tc.GL.Add(tc.Gr, tc.Index) - assert.Equal(tt, tc.Expected.Gr, tc.GL.GroupAt(tc.Expected.Index)) + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + tt.GL.Add(tt.Gr, tt.Index) + assert.Equal(t, tt.Expected.Gr, tt.GL.GroupAt(tt.Expected.Index)) }) } } @@ -441,7 +451,8 @@ func TestGroupList_AddOrMove(t *testing.T) { g2 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g3 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g4 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() - testCases := []struct { + + tests := []struct { Name string GL *GroupList Gr *Group @@ -495,12 +506,12 @@ func TestGroupList_AddOrMove(t *testing.T) { }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - tc.GL.AddOrMove(tc.Gr, tc.Index) - assert.Equal(tt, tc.Expected.Gr, tc.GL.GroupAt(tc.Expected.Index)) + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + tt.GL.AddOrMove(tt.Gr, tt.Index) + assert.Equal(t, tt.Expected.Gr, tt.GL.GroupAt(tt.Expected.Index)) }) } } @@ -510,9 +521,10 @@ func TestGroupList_Move(t *testing.T) { g2 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g3 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g4 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() - testCases := []struct { + + tests := []struct { Name string - GL *GroupList + Target *GroupList Id id.PropertyItemID ToIndex int Expected struct { @@ -527,7 +539,7 @@ func TestGroupList_Move(t *testing.T) { Name: "success", Id: g1.ID(), ToIndex: 2, - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: struct { Id id.PropertyItemID Index int @@ -535,12 +547,12 @@ func TestGroupList_Move(t *testing.T) { }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - tc.GL.Move(tc.Id, tc.ToIndex) - assert.Equal(tt, tc.Expected.Id, tc.GL.GroupAt(tc.Expected.Index).ID()) + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + tt.Target.Move(tt.Id, tt.ToIndex) + assert.Equal(t, tt.Expected.Id, tt.Target.GroupAt(tt.Expected.Index).ID()) }) } } @@ -550,9 +562,10 @@ func TestGroupList_MoveAt(t *testing.T) { g2 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g3 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g4 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() - testCases := []struct { + + tests := []struct { Name string - GL *GroupList + Target *GroupList FromIndex, ToIndex int Expected []*Group }{ @@ -563,31 +576,31 @@ func TestGroupList_MoveAt(t *testing.T) { Name: "from = to", FromIndex: 2, ToIndex: 2, - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: []*Group{g1, g2, g3, g4}, }, { Name: "from < 0", FromIndex: -1, ToIndex: 2, - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: []*Group{g1, g2, g3, g4}, }, { Name: "success move", FromIndex: 0, ToIndex: 2, - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: []*Group{g2, g3, g1, g4}, }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - tc.GL.MoveAt(tc.FromIndex, tc.ToIndex) - assert.Equal(tt, tc.Expected, tc.GL.Groups()) + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + tt.Target.MoveAt(tt.FromIndex, tt.ToIndex) + assert.Equal(t, tt.Expected, tt.Target.Groups()) }) } } @@ -597,9 +610,10 @@ func TestGroupList_RemoveAt(t *testing.T) { g2 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g3 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g4 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() - testCases := []struct { + + tests := []struct { Name string - GL *GroupList + Target *GroupList Index int Expected []*Group }{ @@ -609,40 +623,42 @@ func TestGroupList_RemoveAt(t *testing.T) { { Name: "success", Index: 1, - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: []*Group{g1, g3, g4}, }, { Name: "index < 0", Index: -1, - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: []*Group{g1, g2, g3, g4}, }, { Name: "index > length", Index: 5, - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: []*Group{g1, g2, g3, g4}, }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - tc.GL.RemoveAt(tc.Index) - assert.Equal(tt, tc.Expected, tc.GL.Groups()) + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + tt.Target.RemoveAt(tt.Index) + assert.Equal(t, tt.Expected, tt.Target.Groups()) }) } } + func TestGroupList_Remove(t *testing.T) { g1 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g2 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g3 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g4 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() - testCases := []struct { + + tests := []struct { Name string - GL *GroupList + Target *GroupList Input id.PropertyItemID Expected bool }{ @@ -652,23 +668,23 @@ func TestGroupList_Remove(t *testing.T) { { Name: "success", Input: g1.ID(), - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: true, }, { Name: "not found", Input: g4.ID(), - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3}).MustBuild(), Expected: false, }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - res := tc.GL.Remove(tc.Input) - assert.Equal(tt, tc.Expected, res) + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + res := tt.Target.Remove(tt.Input) + assert.Equal(t, tt.Expected, res) }) } } @@ -677,9 +693,10 @@ func TestGroupList_GetOrCreateField(t *testing.T) { sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() sg := NewSchemaGroup().ID("aa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() g := NewGroup().ID(id.NewPropertyItemID()).Schema(sg.Schema(), sg.ID()).MustBuild() - testCases := []struct { + + tests := []struct { Name string - GL *GroupList + Target *GroupList Schema *Schema Ptr *Pointer Expected struct { @@ -689,7 +706,7 @@ func TestGroupList_GetOrCreateField(t *testing.T) { }{ { Name: "success", - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").Groups([]*Group{g}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").Groups([]*Group{g}).MustBuild(), Schema: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), Ptr: NewPointer(nil, g.ID().Ref(), sf.ID().Ref()), Expected: struct { @@ -697,36 +714,36 @@ func TestGroupList_GetOrCreateField(t *testing.T) { Field *Field }{ Ok: true, - Field: NewField(sf).MustBuild(), + Field: NewField().Field("aa").Value(NewOptionalValue(ValueTypeString, nil)).Build(), }, }, { Name: "can't get a group", - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").MustBuild(), Schema: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), Ptr: NewPointer(nil, g.ID().Ref(), sf.ID().Ref()), }, { Name: "FieldByItem not ok: sg!=nil", - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").Groups([]*Group{g}).MustBuild(), + Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").Groups([]*Group{g}).MustBuild(), Schema: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), Ptr: NewPointer(sg.IDRef(), g.ID().Ref(), sf.ID().Ref()), }, { Name: "psg == nil", - GL: NewGroupList().NewID().Groups([]*Group{g}).MustBuild(), + Target: NewGroupList().NewID().Groups([]*Group{g}).MustBuild(), Schema: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), Ptr: NewPointer(nil, g.ID().Ref(), sf.ID().Ref()), }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - res, ok := tc.GL.GetOrCreateField(tc.Schema, tc.Ptr) - assert.Equal(tt, tc.Expected.Field, res) - assert.Equal(tt, tc.Expected.Ok, ok) + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + res, ok := tt.Target.GetOrCreateField(tt.Schema, tt.Ptr) + assert.Equal(t, tt.Expected.Field, res) + assert.Equal(t, tt.Expected.Ok, ok) }) } } @@ -736,7 +753,8 @@ func TestGroupList_CreateAndAddListItem(t *testing.T) { sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() sg := NewSchemaGroup().ID("aa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() g := NewGroup().ID(id.NewPropertyItemID()).Schema(sg.Schema(), sg.ID()).MustBuild() - testCases := []struct { + + tests := []struct { Name string GL *GroupList Schema *Schema @@ -752,14 +770,14 @@ func TestGroupList_CreateAndAddListItem(t *testing.T) { }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - res := tc.GL.CreateAndAddListItem(tc.Schema, tc.Index) - assert.Equal(tt, tc.Expected.Schema(), res.Schema()) - assert.Equal(tt, tc.Expected.Fields(nil), res.Fields(nil)) - assert.Equal(tt, tc.Expected.SchemaGroup(), res.SchemaGroup()) + for _, tt := range tests { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + res := tt.GL.CreateAndAddListItem(tt.Schema, tt.Index) + assert.Equal(t, tt.Expected.Schema(), res.Schema()) + assert.Equal(t, tt.Expected.Fields(nil), res.Fields(nil)) + assert.Equal(t, tt.Expected.SchemaGroup(), res.SchemaGroup()) }) } } @@ -848,7 +866,7 @@ func TestGroupList_Fields(t *testing.T) { name: "not found", target: testGroupList1, args: args{p: PointFieldOnly("xxxxxx")}, - want: []*Field{}, + want: nil, }, { name: "empty", @@ -897,13 +915,13 @@ func TestGroupList_RemoveFields(t *testing.T) { name: "specified schema group", target: testGroupList1.Clone(), args: args{p: PointItemBySchema(testGroupList1.SchemaGroup())}, - want: nil, + want: []*Field{testField2}, }, { name: "specified item", target: testGroupList1.Clone(), args: args{p: PointItem(testGroupList1.ID())}, - want: nil, + want: []*Field{testField2}, }, { name: "not found", diff --git a/pkg/property/group_test.go b/pkg/property/group_test.go index a086c13a..a4d79a56 100644 --- a/pkg/property/group_test.go +++ b/pkg/property/group_test.go @@ -23,14 +23,13 @@ func TestGroup_SchemaGroup(t *testing.T) { } func TestGroup_HasLinkedField(t *testing.T) { - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") l := dataset.PointAt(id.NewDatasetID(), id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) - f := NewField(sf).Value(OptionalValueFrom(v)).Link(ls).MustBuild() - f2 := NewField(sf).Value(OptionalValueFrom(v)).MustBuild() + f := NewField().Field("a").Value(OptionalValueFrom(v)).Link(ls).Build() + f2 := NewField().Field("a").Value(OptionalValueFrom(v)).Build() - testCases := []struct { + tests := []struct { Name string Group *Group Expected bool @@ -51,7 +50,8 @@ func TestGroup_HasLinkedField(t *testing.T) { Expected: false, }, } - for _, tc := range testCases { + + for _, tc := range tests { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() @@ -60,17 +60,17 @@ func TestGroup_HasLinkedField(t *testing.T) { }) } } + func TestGroup_IsDatasetLinked(t *testing.T) { - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() l := dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID()) ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) - f := NewField(sf).Value(OptionalValueFrom(v)).Link(ls).MustBuild() - f2 := NewField(sf).Value(OptionalValueFrom(v)).MustBuild() + f := NewField().Field("a").Value(OptionalValueFrom(v)).Link(ls).Build() + f2 := NewField().Field("a").Value(OptionalValueFrom(v)).Build() - testCases := []struct { + tests := []struct { Name string Group *Group DatasetSchema id.DatasetSchemaID @@ -93,7 +93,8 @@ func TestGroup_IsDatasetLinked(t *testing.T) { Expected: false, }, } - for _, tc := range testCases { + + for _, tc := range tests { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() @@ -104,14 +105,13 @@ func TestGroup_IsDatasetLinked(t *testing.T) { } func TestGroup_Datasets(t *testing.T) { - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() l := dataset.PointAt(dsid, id.NewDatasetSchemaID(), id.NewDatasetSchemaFieldID()) ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) - f := NewField(sf).Value(OptionalValueFrom(v)).Link(ls).MustBuild() + f := NewField().Field("a").Value(OptionalValueFrom(v)).Link(ls).Build() - testCases := []struct { + tests := []struct { Name string Group *Group Expected []id.DatasetID @@ -127,7 +127,8 @@ func TestGroup_Datasets(t *testing.T) { Expected: []id.DatasetID{dsid}, }, } - for _, tc := range testCases { + + for _, tc := range tests { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() @@ -138,15 +139,14 @@ func TestGroup_Datasets(t *testing.T) { } func TestGroup_FieldsByLinkedDataset(t *testing.T) { - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") dsid := id.NewDatasetID() dssid := id.NewDatasetSchemaID() l := dataset.PointAt(dsid, dssid, id.NewDatasetSchemaFieldID()) ls := dataset.NewGraphPointer([]*dataset.Pointer{l}) - f := NewField(sf).Value(OptionalValueFrom(v)).Link(ls).MustBuild() + f := NewField().Field("a").Value(OptionalValueFrom(v)).Link(ls).Build() - testCases := []struct { + tests := []struct { Name string Group *Group DatasetSchema id.DatasetSchemaID @@ -164,7 +164,8 @@ func TestGroup_FieldsByLinkedDataset(t *testing.T) { Expected: []*Field{f}, }, } - for _, tc := range testCases { + + for _, tc := range tests { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() @@ -175,12 +176,11 @@ func TestGroup_FieldsByLinkedDataset(t *testing.T) { } func TestGroup_IsEmpty(t *testing.T) { - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") - f := NewField(sf).Value(OptionalValueFrom(v)).MustBuild() - f2 := NewField(sf).MustBuild() + f := NewField().Field("a").Value(OptionalValueFrom(v)).Build() + f2 := NewField().Field("a").Build() - testCases := []struct { + tests := []struct { Name string Group *Group Expected bool @@ -197,7 +197,8 @@ func TestGroup_IsEmpty(t *testing.T) { Expected: false, }, } - for _, tc := range testCases { + + for _, tc := range tests { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() @@ -208,17 +209,15 @@ func TestGroup_IsEmpty(t *testing.T) { } func TestGroup_Prune(t *testing.T) { - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") - f := NewField(sf).Value(OptionalValueFrom(v)).MustBuild() - f2 := NewField(sf).MustBuild() + f := NewField().Field("a").Value(OptionalValueFrom(v)).Build() + f2 := NewField().Field("a").Build() - testCases := []struct { + tests := []struct { Name string Group *Group Expected []*Field }{ - { Name: "nil group", }, @@ -228,7 +227,8 @@ func TestGroup_Prune(t *testing.T) { Expected: []*Field{f}, }, } - for _, tc := range testCases { + + for _, tc := range tests { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() @@ -240,9 +240,10 @@ func TestGroup_Prune(t *testing.T) { func TestGroup_GetOrCreateField(t *testing.T) { sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() - f := NewField(sf).MustBuild() + f := NewField().Field("aa").Value(NewOptionalValue(ValueTypeString, nil)).Build() sg := NewSchemaGroup().ID("aa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() - testCases := []struct { + + tests := []struct { Name string Group *Group PS *Schema @@ -273,7 +274,7 @@ func TestGroup_GetOrCreateField(t *testing.T) { Field *Field Bool bool }{ - Field: NewField(sf).MustBuild(), + Field: NewField().Field("aa").Value(NewOptionalValue(ValueTypeString, nil)).Build(), Bool: true, }, }, @@ -286,12 +287,13 @@ func TestGroup_GetOrCreateField(t *testing.T) { Field *Field Bool bool }{ - Field: NewField(sf).MustBuild(), + Field: NewField().Field("aa").Value(NewOptionalValue(ValueTypeString, nil)).Build(), Bool: false, }, }, } - for _, tc := range testCases { + + for _, tc := range tests { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() @@ -303,13 +305,11 @@ func TestGroup_GetOrCreateField(t *testing.T) { } func TestGroup_RemoveField(t *testing.T) { - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() - sf2 := NewSchemaField().ID("b").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") - f := NewField(sf).Value(OptionalValueFrom(v)).MustBuild() - f2 := NewField(sf2).MustBuild() + f := NewField().Field("a").Value(OptionalValueFrom(v)).Build() + f2 := NewField().Field("b").Build() - testCases := []struct { + tests := []struct { Name string Group *Group Input id.PropertySchemaFieldID @@ -326,7 +326,8 @@ func TestGroup_RemoveField(t *testing.T) { Expected: []*Field{f}, }, } - for _, tc := range testCases { + + for _, tc := range tests { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() @@ -337,13 +338,11 @@ func TestGroup_RemoveField(t *testing.T) { } func TestGroup_FieldIDs(t *testing.T) { - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() - sf2 := NewSchemaField().ID("b").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") - f := NewField(sf).Value(OptionalValueFrom(v)).MustBuild() - f2 := NewField(sf2).MustBuild() + f := NewField().Field("a").Value(OptionalValueFrom(v)).Build() + f2 := NewField().Field("b").Value(NewOptionalValue(ValueTypeString, nil)).Build() - testCases := []struct { + tests := []struct { Name string Group *Group Expected []id.PropertySchemaFieldID @@ -358,7 +357,8 @@ func TestGroup_FieldIDs(t *testing.T) { Expected: []id.PropertySchemaFieldID{"a", "b"}, }, } - for _, tc := range testCases { + + for _, tc := range tests { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() @@ -369,13 +369,11 @@ func TestGroup_FieldIDs(t *testing.T) { } func TestGroup_Field(t *testing.T) { - sf := NewSchemaField().ID("a").Type(ValueTypeString).MustBuild() - sf2 := NewSchemaField().ID("b").Type(ValueTypeString).MustBuild() v := ValueTypeString.ValueFrom("vvv") - f := NewField(sf).Value(OptionalValueFrom(v)).MustBuild() - f2 := NewField(sf2).MustBuild() + f := NewField().Field("a").Value(OptionalValueFrom(v)).Build() + f2 := NewField().Field("b").Build() - testCases := []struct { + tests := []struct { Name string Group *Group Input id.PropertySchemaFieldID @@ -398,7 +396,8 @@ func TestGroup_Field(t *testing.T) { Expected: nil, }, } - for _, tc := range testCases { + + for _, tc := range tests { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() @@ -410,10 +409,10 @@ func TestGroup_Field(t *testing.T) { func TestGroup_UpdateNameFieldValue(t *testing.T) { sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() - //f := NewField(sf).MustBuild() sg := NewSchemaGroup().ID("aa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() sg2 := NewSchemaGroup().ID("bb").Schema(id.MustPropertySchemaID("xx~1.0.0/bb")).Fields([]*SchemaField{sf}).MustBuild() - testCases := []struct { + + tests := []struct { Name string Group *Group PS *Schema @@ -440,7 +439,7 @@ func TestGroup_UpdateNameFieldValue(t *testing.T) { PS: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), Value: ValueTypeString.ValueFrom("abc"), FID: "aa", - Expected: NewField(sf).Value(OptionalValueFrom(ValueTypeString.ValueFrom("abc"))).MustBuild(), + Expected: NewField().Field("a").Value(OptionalValueFrom(ValueTypeString.ValueFrom("abc"))).Build(), }, { Name: "invalid property field", @@ -452,7 +451,8 @@ func TestGroup_UpdateNameFieldValue(t *testing.T) { Err: ErrInvalidPropertyField, }, } - for _, tc := range testCases { + + for _, tc := range tests { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() diff --git a/pkg/property/initializer.go b/pkg/property/initializer.go index 07c33245..f352b421 100644 --- a/pkg/property/initializer.go +++ b/pkg/property/initializer.go @@ -277,7 +277,7 @@ func (p *InitializerField) PropertyField() *Field { plinks = dataset.NewGraphPointer(links) } - return NewFieldUnsafe().LinksUnsafe(plinks).FieldUnsafe(p.Field).ValueUnsafe(NewOptionalValue(p.Type, p.Value.Clone())).Build() + return NewField().Link(plinks).Field(p.Field).Value(NewOptionalValue(p.Type, p.Value.Clone())).Build() } type InitializerLink struct { diff --git a/pkg/property/initializer_test.go b/pkg/property/initializer_test.go index 67bdc1ac..a916a985 100644 --- a/pkg/property/initializer_test.go +++ b/pkg/property/initializer_test.go @@ -147,7 +147,7 @@ func TestInitializerItem_PropertyGroup(t *testing.T) { } expected := NewItem().ID(*item.ID).Schema(parent, item.SchemaItem).Group().Fields([]*Field{ - NewFieldUnsafe().FieldUnsafe(item.Fields[0].Field).ValueUnsafe(NewOptionalValue(item.Fields[0].Type, item.Fields[0].Value)).Build(), + NewField().Field(item.Fields[0].Field).Value(NewOptionalValue(item.Fields[0].Type, item.Fields[0].Value)).Build(), }).MustBuild() assert.Equal(t, expected, item.PropertyGroup(parent)) @@ -214,7 +214,7 @@ func TestInitializerGroup_PropertyGroup(t *testing.T) { } expected := NewItem().ID(*item.ID).Schema(parent, parentItem).Group().Fields([]*Field{ - NewFieldUnsafe().FieldUnsafe(item.Fields[0].Field).ValueUnsafe(NewOptionalValue(item.Fields[0].Type, item.Fields[0].Value)).Build(), + NewField().Field(item.Fields[0].Field).Value(NewOptionalValue(item.Fields[0].Type, item.Fields[0].Value)).Build(), }).MustBuild() p, err := item.PropertyGroup(parent, parentItem) @@ -258,10 +258,10 @@ func TestInitializerField_PropertyField(t *testing.T) { }}, } - expected := NewFieldUnsafe(). - FieldUnsafe(field.Field). - ValueUnsafe(NewOptionalValue(field.Type, field.Value)). - LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(*field.Links[0].Dataset.CopyRef(), field.Links[0].Schema, field.Links[0].Field)})). + expected := NewField(). + Field(field.Field). + Value(NewOptionalValue(field.Type, field.Value)). + Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(*field.Links[0].Dataset.CopyRef(), field.Links[0].Schema, field.Links[0].Field)})). Build() assert.Equal(t, expected, field.PropertyField()) diff --git a/pkg/property/item_test.go b/pkg/property/item_test.go index 8ff6eff3..780878dd 100644 --- a/pkg/property/item_test.go +++ b/pkg/property/item_test.go @@ -57,9 +57,9 @@ func TestToGroup(t *testing.T) { il := []Item{ NewGroup().ID(iid).Schema(propertySchemaID, propertySchemaGroup1ID). Fields([]*Field{ - NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). + NewField(). + Field(propertySchemaField1ID). + Value(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). Build(), }).MustBuild(), } diff --git a/pkg/property/merged_test.go b/pkg/property/merged_test.go index ac4e5ef7..a6816784 100644 --- a/pkg/property/merged_test.go +++ b/pkg/property/merged_test.go @@ -32,17 +32,17 @@ func TestMerge(t *testing.T) { i8id := id.NewPropertyItemID() fields1 := []*Field{ - NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("a")).ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("a"))).Build(), - NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("b")).ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("b"))).Build(), - NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("e")).ValueUnsafe(NewOptionalValue(ValueTypeString, nil)).LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d2, ds, df)})).Build(), - NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("f")).ValueUnsafe(NewOptionalValue(ValueTypeNumber, nil)).Build(), + NewField().Field(id.PropertySchemaFieldID("a")).Value(OptionalValueFrom(ValueTypeString.ValueFrom("a"))).Build(), + NewField().Field(id.PropertySchemaFieldID("b")).Value(OptionalValueFrom(ValueTypeString.ValueFrom("b"))).Build(), + NewField().Field(id.PropertySchemaFieldID("e")).Value(NewOptionalValue(ValueTypeString, nil)).Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAt(d2, ds, df)})).Build(), + NewField().Field(id.PropertySchemaFieldID("f")).Value(NewOptionalValue(ValueTypeNumber, nil)).Build(), } fields2 := []*Field{ - NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("a")).ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("1"))).Build(), - NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("c")).ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("2"))).Build(), - NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("d")).ValueUnsafe(NewOptionalValue(ValueTypeString, nil)).LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAtField(ds, df)})).Build(), - NewFieldUnsafe().FieldUnsafe(id.PropertySchemaFieldID("f")).ValueUnsafe(NewOptionalValue(ValueTypeString, nil)).Build(), + NewField().Field(id.PropertySchemaFieldID("a")).Value(OptionalValueFrom(ValueTypeString.ValueFrom("1"))).Build(), + NewField().Field(id.PropertySchemaFieldID("c")).Value(OptionalValueFrom(ValueTypeString.ValueFrom("2"))).Build(), + NewField().Field(id.PropertySchemaFieldID("d")).Value(NewOptionalValue(ValueTypeString, nil)).Link(dataset.NewGraphPointer([]*dataset.Pointer{dataset.PointAtField(ds, df)})).Build(), + NewField().Field(id.PropertySchemaFieldID("f")).Value(NewOptionalValue(ValueTypeString, nil)).Build(), } groups1 := []*Group{ diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index f34fdce8..7b55424b 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -56,40 +56,42 @@ func TestPropertyMigrateSchema(t *testing.T) { fields := []*Field{ // should remain - NewFieldUnsafe().FieldUnsafe(schemaField1ID). - ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("foobar"))). + NewField().Field(schemaField1ID). + Value(OptionalValueFrom(ValueTypeString.ValueFrom("foobar"))). Build(), // should be removed because of max - NewFieldUnsafe().FieldUnsafe(schemaField2ID). - ValueUnsafe(OptionalValueFrom(ValueTypeNumber.ValueFrom(101))). + NewField().Field(schemaField2ID). + Value(OptionalValueFrom(ValueTypeNumber.ValueFrom(101))). Build(), // should remain - NewFieldUnsafe().FieldUnsafe(schemaField3ID). - ValueUnsafe(OptionalValueFrom(ValueTypeNumber.ValueFrom(1))). + NewField().Field(schemaField3ID). + Value(OptionalValueFrom(ValueTypeNumber.ValueFrom(1))). Build(), // should be removed because of choices - NewFieldUnsafe().FieldUnsafe(schemaField4ID). - ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("z"))). + NewField().Field(schemaField4ID). + Value(OptionalValueFrom(ValueTypeString.ValueFrom("z"))). Build(), // should remain - NewFieldUnsafe().FieldUnsafe(schemaField5ID). - LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{ + NewField().Field(schemaField5ID). + Value(NewOptionalValue(ValueTypeString, nil)). + Link(dataset.NewGraphPointer([]*dataset.Pointer{ dataset.PointAt(datasetID, datasetSchemaID, datasetFieldID), })). Build(), // should be removed because of linked dataset field value type - NewFieldUnsafe().FieldUnsafe(schemaField6ID). - LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{ + NewField().Field(schemaField6ID). + Value(NewOptionalValue(ValueTypeNumber, nil)). + Link(dataset.NewGraphPointer([]*dataset.Pointer{ dataset.PointAt(datasetID, datasetSchemaID, datasetFieldID), })). Build(), // should be removed because of type - NewFieldUnsafe().FieldUnsafe(schemaField7ID). - ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("hogehoge"))). + NewField().Field(schemaField7ID). + Value(OptionalValueFrom(ValueTypeString.ValueFrom("hogehoge"))). Build(), // should be removed because of not existing field - NewFieldUnsafe().FieldUnsafe(schemaField8ID). - ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("hogehoge"))). + NewField().Field(schemaField8ID). + Value(OptionalValueFrom(ValueTypeString.ValueFrom("hogehoge"))). Build(), } items := []Item{ @@ -379,6 +381,12 @@ func TestProperty_RemoveFields(t *testing.T) { args: args{p: PointFieldOnly(testField1.Field())}, want: []*Field{testField2}, }, + { + name: "item only", + target: testProperty1.Clone(), + args: args{p: PointItem(testGroupList1.ID())}, + want: []*Field{testField1, testField2}, + }, { name: "not found", target: testProperty1.Clone(), @@ -413,8 +421,8 @@ func TestProperty_MoveFields(t *testing.T) { sg3 := SchemaGroupID("ccc") sg4 := SchemaGroupID("ddd") - f1 := NewFieldUnsafe().FieldUnsafe(FieldID("x")).ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("aaa"))).Build() - f2 := NewFieldUnsafe().FieldUnsafe(FieldID("y")).ValueUnsafe(OptionalValueFrom(ValueTypeString.ValueFrom("bbb"))).Build() + f1 := NewField().Field(FieldID("x")).Value(OptionalValueFrom(ValueTypeString.ValueFrom("aaa"))).Build() + f2 := NewField().Field(FieldID("y")).Value(OptionalValueFrom(ValueTypeString.ValueFrom("bbb"))).Build() p := New().NewID().Scene(id.NewSceneID()).Schema(testSchema1.ID()).Items([]Item{ NewGroup().NewID().Schema(testSchema1.ID(), sg1).Fields([]*Field{ f1, diff --git a/pkg/scene/builder/builder_test.go b/pkg/scene/builder/builder_test.go index 75a79070..8a907743 100644 --- a/pkg/scene/builder/builder_test.go +++ b/pkg/scene/builder/builder_test.go @@ -75,13 +75,13 @@ func TestSceneBuilder(t *testing.T) { Items([]property.Item{ property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). Fields([]*property.Field{ - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("xxx"))). + property.NewField(). + Field(propertySchemaField1ID). + Value(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("xxx"))). Build(), - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField2ID). - ValueUnsafe(property.OptionalValueFrom(property.ValueTypeNumber.ValueFrom(1))). + property.NewField(). + Field(propertySchemaField2ID). + Value(property.OptionalValueFrom(property.ValueTypeNumber.ValueFrom(1))). Build(), }).MustBuild(), }). @@ -102,13 +102,13 @@ func TestSceneBuilder(t *testing.T) { Items([]property.Item{ property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). Fields([]*property.Field{ - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("yyy"))). + property.NewField(). + Field(propertySchemaField1ID). + Value(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("yyy"))). Build(), - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField2ID). - ValueUnsafe(property.OptionalValueFrom(property.ValueTypeNumber.ValueFrom(1))). + property.NewField(). + Field(propertySchemaField2ID). + Value(property.OptionalValueFrom(property.ValueTypeNumber.ValueFrom(1))). Build(), }).MustBuild(), }). @@ -127,13 +127,13 @@ func TestSceneBuilder(t *testing.T) { Items([]property.Item{ property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). Fields([]*property.Field{ - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("xxx"))). + property.NewField(). + Field(propertySchemaField1ID). + Value(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("xxx"))). Build(), - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField3ID). - ValueUnsafe(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("test"))). + property.NewField(). + Field(propertySchemaField3ID). + Value(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("test"))). Build(), }).MustBuild(), }). @@ -160,10 +160,10 @@ func TestSceneBuilder(t *testing.T) { Items([]property.Item{ property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). Fields([]*property.Field{ - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(property.NewOptionalValue(property.ValueTypeString, nil)). - LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{ + property.NewField(). + Field(propertySchemaField1ID). + Value(property.NewOptionalValue(property.ValueTypeString, nil)). + Link(dataset.NewGraphPointer([]*dataset.Pointer{ dataset.PointAt(ds2id, dss2id, ds2f1), dataset.PointAt(ds3id, dss3id, ds3f1), })). @@ -192,9 +192,9 @@ func TestSceneBuilder(t *testing.T) { Items([]property.Item{ property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). Fields([]*property.Field{ - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField2ID). - ValueUnsafe(property.OptionalValueFrom(property.ValueTypeNumber.ValueFrom(1))). + property.NewField(). + Field(propertySchemaField2ID). + Value(property.OptionalValueFrom(property.ValueTypeNumber.ValueFrom(1))). Build(), }).MustBuild(), }). @@ -219,16 +219,16 @@ func TestSceneBuilder(t *testing.T) { Items([]property.Item{ property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). Fields([]*property.Field{ - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(property.NewOptionalValue(property.ValueTypeString, nil)). - LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{ + property.NewField(). + Field(propertySchemaField1ID). + Value(property.NewOptionalValue(property.ValueTypeString, nil)). + Link(dataset.NewGraphPointer([]*dataset.Pointer{ dataset.PointAtField(dss3id, ds3f1), })). Build(), - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField3ID). - ValueUnsafe(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("xxx"))). + property.NewField(). + Field(propertySchemaField3ID). + Value(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("xxx"))). Build(), }).MustBuild(), }). @@ -256,10 +256,10 @@ func TestSceneBuilder(t *testing.T) { Items([]property.Item{ property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). Fields([]*property.Field{ - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(property.NewOptionalValue(property.ValueTypeString, nil)). - LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{ + property.NewField(). + Field(propertySchemaField1ID). + Value(property.NewOptionalValue(property.ValueTypeString, nil)). + Link(dataset.NewGraphPointer([]*dataset.Pointer{ dataset.PointAtField(dss1id, ds1f2), })). Build(), @@ -281,19 +281,19 @@ func TestSceneBuilder(t *testing.T) { Items([]property.Item{ property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). Fields([]*property.Field{ - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(property.NewOptionalValue(property.ValueTypeString, nil)). - LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{ + property.NewField(). + Field(propertySchemaField1ID). + Value(property.NewOptionalValue(property.ValueTypeString, nil)). + Link(dataset.NewGraphPointer([]*dataset.Pointer{ dataset.PointAtField(dss1id, ds1f1), dataset.PointAtField(dss2id, ds2f1), dataset.PointAtField(dss3id, ds3f1), })). Build(), - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField2ID). - ValueUnsafe(property.NewOptionalValue(property.ValueTypeString, nil)). - LinksUnsafe(dataset.NewGraphPointer([]*dataset.Pointer{ + property.NewField(). + Field(propertySchemaField2ID). + Value(property.NewOptionalValue(property.ValueTypeString, nil)). + Link(dataset.NewGraphPointer([]*dataset.Pointer{ dataset.PointAtField(dss1id, ds1f1), dataset.PointAtField(dss2id, ds2f1), dataset.PointAtField(dss3id, ds3f1), @@ -319,16 +319,16 @@ func TestSceneBuilder(t *testing.T) { property.NewGroupList().NewID().Schema(propertySchemaID, propertySchemaGroup2ID).Groups([]*property.Group{ property.NewGroup().ID(propertyItemID1).Schema(propertySchemaID, propertySchemaGroup2ID). Fields([]*property.Field{ - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("XYZ"))). + property.NewField(). + Field(propertySchemaField1ID). + Value(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("XYZ"))). Build(), }).MustBuild(), property.NewGroup().ID(propertyItemID2).Schema(propertySchemaID, propertySchemaGroup2ID). Fields([]*property.Field{ - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("ZYX"))). + property.NewField(). + Field(propertySchemaField1ID). + Value(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("ZYX"))). Build(), }).MustBuild(), }).MustBuild(), @@ -359,9 +359,9 @@ func TestSceneBuilder(t *testing.T) { Schema(propertySchemaID). Items([]property.Item{ property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID).Fields([]*property.Field{ - property.NewFieldUnsafe(). - FieldUnsafe(propertySchemaField1ID). - ValueUnsafe(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("hogehoge"))). + property.NewField(). + Field(propertySchemaField1ID). + Value(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("hogehoge"))). Build(), }).MustBuild(), }). From e7e2f711ee8b251f253b12cb3b6480394ec66b9b Mon Sep 17 00:00:00 2001 From: rot1024 Date: Fri, 10 Dec 2021 20:45:38 +0900 Subject: [PATCH 19/55] return nil from id.ID.Ref if id is nil --- pkg/id/asset_gen.go | 14 ++++++++++---- pkg/id/cluster_gen.go | 14 ++++++++++---- pkg/id/dataset_gen.go | 14 ++++++++++---- pkg/id/dataset_schema_field_gen.go | 14 ++++++++++---- pkg/id/dataset_schema_gen.go | 14 ++++++++++---- pkg/id/id.go | 2 +- pkg/id/id.tmpl | 14 ++++++++++---- pkg/id/id_test.go | 6 ++---- pkg/id/infobox_field_gen.go | 14 ++++++++++---- pkg/id/layer_gen.go | 14 ++++++++++---- pkg/id/project_gen.go | 14 ++++++++++---- pkg/id/property_gen.go | 14 ++++++++++---- pkg/id/property_item_gen.go | 14 ++++++++++---- pkg/id/scene_gen.go | 14 ++++++++++---- pkg/id/tag_gen.go | 14 ++++++++++---- pkg/id/team_gen.go | 14 ++++++++++---- pkg/id/user_gen.go | 14 ++++++++++---- pkg/id/widget_gen.go | 14 ++++++++++---- 18 files changed, 163 insertions(+), 69 deletions(-) diff --git a/pkg/id/asset_gen.go b/pkg/id/asset_gen.go index fa061e5c..bbd868e5 100644 --- a/pkg/id/asset_gen.go +++ b/pkg/id/asset_gen.go @@ -44,7 +44,7 @@ func AssetIDFromRef(i *string) *AssetID { // AssetIDFromRefID generates a new AssetID from a ref of a generic ID. func AssetIDFromRefID(i *ID) *AssetID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := AssetID(*i) @@ -68,12 +68,18 @@ func (d AssetID) GoString() string { // RefString returns a reference of string representation. func (d AssetID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d AssetID) Ref() *AssetID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d AssetID) Contains(ids []AssetID) bool { // CopyRef returns a copy of a reference. func (d *AssetID) CopyRef() *AssetID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *AssetID) CopyRef() *AssetID { // IDRef returns a reference of a domain id. func (d *AssetID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *AssetID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *AssetID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/cluster_gen.go b/pkg/id/cluster_gen.go index 3720b1bf..fdb5aa90 100644 --- a/pkg/id/cluster_gen.go +++ b/pkg/id/cluster_gen.go @@ -44,7 +44,7 @@ func ClusterIDFromRef(i *string) *ClusterID { // ClusterIDFromRefID generates a new ClusterID from a ref of a generic ID. func ClusterIDFromRefID(i *ID) *ClusterID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := ClusterID(*i) @@ -68,12 +68,18 @@ func (d ClusterID) GoString() string { // RefString returns a reference of string representation. func (d ClusterID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d ClusterID) Ref() *ClusterID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d ClusterID) Contains(ids []ClusterID) bool { // CopyRef returns a copy of a reference. func (d *ClusterID) CopyRef() *ClusterID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *ClusterID) CopyRef() *ClusterID { // IDRef returns a reference of a domain id. func (d *ClusterID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *ClusterID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *ClusterID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/dataset_gen.go b/pkg/id/dataset_gen.go index 1e76621b..db57cdbd 100644 --- a/pkg/id/dataset_gen.go +++ b/pkg/id/dataset_gen.go @@ -44,7 +44,7 @@ func DatasetIDFromRef(i *string) *DatasetID { // DatasetIDFromRefID generates a new DatasetID from a ref of a generic ID. func DatasetIDFromRefID(i *ID) *DatasetID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := DatasetID(*i) @@ -68,12 +68,18 @@ func (d DatasetID) GoString() string { // RefString returns a reference of string representation. func (d DatasetID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d DatasetID) Ref() *DatasetID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d DatasetID) Contains(ids []DatasetID) bool { // CopyRef returns a copy of a reference. func (d *DatasetID) CopyRef() *DatasetID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *DatasetID) CopyRef() *DatasetID { // IDRef returns a reference of a domain id. func (d *DatasetID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *DatasetID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *DatasetID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/dataset_schema_field_gen.go b/pkg/id/dataset_schema_field_gen.go index b26c073e..18b6e47d 100644 --- a/pkg/id/dataset_schema_field_gen.go +++ b/pkg/id/dataset_schema_field_gen.go @@ -44,7 +44,7 @@ func DatasetSchemaFieldIDFromRef(i *string) *DatasetSchemaFieldID { // DatasetSchemaFieldIDFromRefID generates a new DatasetSchemaFieldID from a ref of a generic ID. func DatasetSchemaFieldIDFromRefID(i *ID) *DatasetSchemaFieldID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := DatasetSchemaFieldID(*i) @@ -68,12 +68,18 @@ func (d DatasetSchemaFieldID) GoString() string { // RefString returns a reference of string representation. func (d DatasetSchemaFieldID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d DatasetSchemaFieldID) Ref() *DatasetSchemaFieldID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d DatasetSchemaFieldID) Contains(ids []DatasetSchemaFieldID) bool { // CopyRef returns a copy of a reference. func (d *DatasetSchemaFieldID) CopyRef() *DatasetSchemaFieldID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *DatasetSchemaFieldID) CopyRef() *DatasetSchemaFieldID { // IDRef returns a reference of a domain id. func (d *DatasetSchemaFieldID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *DatasetSchemaFieldID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *DatasetSchemaFieldID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/dataset_schema_gen.go b/pkg/id/dataset_schema_gen.go index 2c47eeb7..be261801 100644 --- a/pkg/id/dataset_schema_gen.go +++ b/pkg/id/dataset_schema_gen.go @@ -44,7 +44,7 @@ func DatasetSchemaIDFromRef(i *string) *DatasetSchemaID { // DatasetSchemaIDFromRefID generates a new DatasetSchemaID from a ref of a generic ID. func DatasetSchemaIDFromRefID(i *ID) *DatasetSchemaID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := DatasetSchemaID(*i) @@ -68,12 +68,18 @@ func (d DatasetSchemaID) GoString() string { // RefString returns a reference of string representation. func (d DatasetSchemaID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d DatasetSchemaID) Ref() *DatasetSchemaID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d DatasetSchemaID) Contains(ids []DatasetSchemaID) bool { // CopyRef returns a copy of a reference. func (d *DatasetSchemaID) CopyRef() *DatasetSchemaID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *DatasetSchemaID) CopyRef() *DatasetSchemaID { // IDRef returns a reference of a domain id. func (d *DatasetSchemaID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *DatasetSchemaID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *DatasetSchemaID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/id.go b/pkg/id/id.go index 8645ad07..c821a30e 100644 --- a/pkg/id/id.go +++ b/pkg/id/id.go @@ -53,7 +53,7 @@ func FromID(id string) (ID, error) { } func FromIDRef(id *string) *ID { - if id == nil { + if id == nil || *id == "" { return nil } parsedID, err := parseID(*id) diff --git a/pkg/id/id.tmpl b/pkg/id/id.tmpl index aad5207d..6276cb0c 100644 --- a/pkg/id/id.tmpl +++ b/pkg/id/id.tmpl @@ -44,7 +44,7 @@ func {{$name}}IDFromRef(i *string) *{{$name}}ID { // {{$name}}IDFromRefID generates a new {{$name}}ID from a ref of a generic ID. func {{$name}}IDFromRefID(i *ID) *{{$name}}ID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := {{$name}}ID(*i) @@ -68,12 +68,18 @@ func (d {{$name}}ID) GoString() string { // RefString returns a reference of string representation. func (d {{$name}}ID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d {{$name}}ID) Ref() *{{$name}}ID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d {{$name}}ID) Contains(ids []{{$name}}ID) bool { // CopyRef returns a copy of a reference. func (d *{{$name}}ID) CopyRef() *{{$name}}ID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *{{$name}}ID) CopyRef() *{{$name}}ID { // IDRef returns a reference of a domain id. func (d *{{$name}}ID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *{{$name}}ID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *{{$name}}ID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/id_test.go b/pkg/id/id_test.go index 2becc4dc..0b90dada 100644 --- a/pkg/id/id_test.go +++ b/pkg/id/id_test.go @@ -331,13 +331,11 @@ func TestID_generateAllID(t *testing.T) { func TestID_parseID(t *testing.T) { _, err := parseID("") - - assert.True(t, errors.As(ErrInvalidID, &err)) + assert.Error(t, err) id, err := parseID("01f2r7kg1fvvffp0gmexgy5hxy") - assert.Nil(t, err) - assert.EqualValues(t, strings.ToLower(id.String()), "01f2r7kg1fvvffp0gmexgy5hxy") + assert.Equal(t, strings.ToLower(id.String()), "01f2r7kg1fvvffp0gmexgy5hxy") } func TestID_includeUpperCase(t *testing.T) { diff --git a/pkg/id/infobox_field_gen.go b/pkg/id/infobox_field_gen.go index 40758876..acd9ac12 100644 --- a/pkg/id/infobox_field_gen.go +++ b/pkg/id/infobox_field_gen.go @@ -44,7 +44,7 @@ func InfoboxFieldIDFromRef(i *string) *InfoboxFieldID { // InfoboxFieldIDFromRefID generates a new InfoboxFieldID from a ref of a generic ID. func InfoboxFieldIDFromRefID(i *ID) *InfoboxFieldID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := InfoboxFieldID(*i) @@ -68,12 +68,18 @@ func (d InfoboxFieldID) GoString() string { // RefString returns a reference of string representation. func (d InfoboxFieldID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d InfoboxFieldID) Ref() *InfoboxFieldID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d InfoboxFieldID) Contains(ids []InfoboxFieldID) bool { // CopyRef returns a copy of a reference. func (d *InfoboxFieldID) CopyRef() *InfoboxFieldID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *InfoboxFieldID) CopyRef() *InfoboxFieldID { // IDRef returns a reference of a domain id. func (d *InfoboxFieldID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *InfoboxFieldID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *InfoboxFieldID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/layer_gen.go b/pkg/id/layer_gen.go index d49abdcf..f4703056 100644 --- a/pkg/id/layer_gen.go +++ b/pkg/id/layer_gen.go @@ -44,7 +44,7 @@ func LayerIDFromRef(i *string) *LayerID { // LayerIDFromRefID generates a new LayerID from a ref of a generic ID. func LayerIDFromRefID(i *ID) *LayerID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := LayerID(*i) @@ -68,12 +68,18 @@ func (d LayerID) GoString() string { // RefString returns a reference of string representation. func (d LayerID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d LayerID) Ref() *LayerID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d LayerID) Contains(ids []LayerID) bool { // CopyRef returns a copy of a reference. func (d *LayerID) CopyRef() *LayerID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *LayerID) CopyRef() *LayerID { // IDRef returns a reference of a domain id. func (d *LayerID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *LayerID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *LayerID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/project_gen.go b/pkg/id/project_gen.go index 883d8c1a..8ced2d39 100644 --- a/pkg/id/project_gen.go +++ b/pkg/id/project_gen.go @@ -44,7 +44,7 @@ func ProjectIDFromRef(i *string) *ProjectID { // ProjectIDFromRefID generates a new ProjectID from a ref of a generic ID. func ProjectIDFromRefID(i *ID) *ProjectID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := ProjectID(*i) @@ -68,12 +68,18 @@ func (d ProjectID) GoString() string { // RefString returns a reference of string representation. func (d ProjectID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d ProjectID) Ref() *ProjectID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d ProjectID) Contains(ids []ProjectID) bool { // CopyRef returns a copy of a reference. func (d *ProjectID) CopyRef() *ProjectID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *ProjectID) CopyRef() *ProjectID { // IDRef returns a reference of a domain id. func (d *ProjectID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *ProjectID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *ProjectID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/property_gen.go b/pkg/id/property_gen.go index f0cfdbf2..cd7b9474 100644 --- a/pkg/id/property_gen.go +++ b/pkg/id/property_gen.go @@ -44,7 +44,7 @@ func PropertyIDFromRef(i *string) *PropertyID { // PropertyIDFromRefID generates a new PropertyID from a ref of a generic ID. func PropertyIDFromRefID(i *ID) *PropertyID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := PropertyID(*i) @@ -68,12 +68,18 @@ func (d PropertyID) GoString() string { // RefString returns a reference of string representation. func (d PropertyID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d PropertyID) Ref() *PropertyID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d PropertyID) Contains(ids []PropertyID) bool { // CopyRef returns a copy of a reference. func (d *PropertyID) CopyRef() *PropertyID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *PropertyID) CopyRef() *PropertyID { // IDRef returns a reference of a domain id. func (d *PropertyID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *PropertyID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *PropertyID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/property_item_gen.go b/pkg/id/property_item_gen.go index 122e9b1a..681159cc 100644 --- a/pkg/id/property_item_gen.go +++ b/pkg/id/property_item_gen.go @@ -44,7 +44,7 @@ func PropertyItemIDFromRef(i *string) *PropertyItemID { // PropertyItemIDFromRefID generates a new PropertyItemID from a ref of a generic ID. func PropertyItemIDFromRefID(i *ID) *PropertyItemID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := PropertyItemID(*i) @@ -68,12 +68,18 @@ func (d PropertyItemID) GoString() string { // RefString returns a reference of string representation. func (d PropertyItemID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d PropertyItemID) Ref() *PropertyItemID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d PropertyItemID) Contains(ids []PropertyItemID) bool { // CopyRef returns a copy of a reference. func (d *PropertyItemID) CopyRef() *PropertyItemID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *PropertyItemID) CopyRef() *PropertyItemID { // IDRef returns a reference of a domain id. func (d *PropertyItemID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *PropertyItemID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *PropertyItemID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/scene_gen.go b/pkg/id/scene_gen.go index bc8d2c37..c1e870a0 100644 --- a/pkg/id/scene_gen.go +++ b/pkg/id/scene_gen.go @@ -44,7 +44,7 @@ func SceneIDFromRef(i *string) *SceneID { // SceneIDFromRefID generates a new SceneID from a ref of a generic ID. func SceneIDFromRefID(i *ID) *SceneID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := SceneID(*i) @@ -68,12 +68,18 @@ func (d SceneID) GoString() string { // RefString returns a reference of string representation. func (d SceneID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d SceneID) Ref() *SceneID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d SceneID) Contains(ids []SceneID) bool { // CopyRef returns a copy of a reference. func (d *SceneID) CopyRef() *SceneID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *SceneID) CopyRef() *SceneID { // IDRef returns a reference of a domain id. func (d *SceneID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *SceneID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *SceneID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/tag_gen.go b/pkg/id/tag_gen.go index 1e2df781..e04d731b 100644 --- a/pkg/id/tag_gen.go +++ b/pkg/id/tag_gen.go @@ -44,7 +44,7 @@ func TagIDFromRef(i *string) *TagID { // TagIDFromRefID generates a new TagID from a ref of a generic ID. func TagIDFromRefID(i *ID) *TagID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := TagID(*i) @@ -68,12 +68,18 @@ func (d TagID) GoString() string { // RefString returns a reference of string representation. func (d TagID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d TagID) Ref() *TagID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d TagID) Contains(ids []TagID) bool { // CopyRef returns a copy of a reference. func (d *TagID) CopyRef() *TagID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *TagID) CopyRef() *TagID { // IDRef returns a reference of a domain id. func (d *TagID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *TagID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *TagID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/team_gen.go b/pkg/id/team_gen.go index fa5fbc25..2cf47ff9 100644 --- a/pkg/id/team_gen.go +++ b/pkg/id/team_gen.go @@ -44,7 +44,7 @@ func TeamIDFromRef(i *string) *TeamID { // TeamIDFromRefID generates a new TeamID from a ref of a generic ID. func TeamIDFromRefID(i *ID) *TeamID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := TeamID(*i) @@ -68,12 +68,18 @@ func (d TeamID) GoString() string { // RefString returns a reference of string representation. func (d TeamID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d TeamID) Ref() *TeamID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d TeamID) Contains(ids []TeamID) bool { // CopyRef returns a copy of a reference. func (d *TeamID) CopyRef() *TeamID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *TeamID) CopyRef() *TeamID { // IDRef returns a reference of a domain id. func (d *TeamID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *TeamID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *TeamID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/user_gen.go b/pkg/id/user_gen.go index 830d5f53..de7e6787 100644 --- a/pkg/id/user_gen.go +++ b/pkg/id/user_gen.go @@ -44,7 +44,7 @@ func UserIDFromRef(i *string) *UserID { // UserIDFromRefID generates a new UserID from a ref of a generic ID. func UserIDFromRefID(i *ID) *UserID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := UserID(*i) @@ -68,12 +68,18 @@ func (d UserID) GoString() string { // RefString returns a reference of string representation. func (d UserID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d UserID) Ref() *UserID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d UserID) Contains(ids []UserID) bool { // CopyRef returns a copy of a reference. func (d *UserID) CopyRef() *UserID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *UserID) CopyRef() *UserID { // IDRef returns a reference of a domain id. func (d *UserID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *UserID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *UserID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() diff --git a/pkg/id/widget_gen.go b/pkg/id/widget_gen.go index 52028e49..713ff901 100644 --- a/pkg/id/widget_gen.go +++ b/pkg/id/widget_gen.go @@ -44,7 +44,7 @@ func WidgetIDFromRef(i *string) *WidgetID { // WidgetIDFromRefID generates a new WidgetID from a ref of a generic ID. func WidgetIDFromRefID(i *ID) *WidgetID { - if i == nil { + if i == nil || i.IsNil() { return nil } nid := WidgetID(*i) @@ -68,12 +68,18 @@ func (d WidgetID) GoString() string { // RefString returns a reference of string representation. func (d WidgetID) RefString() *string { + if d.IsNil() { + return nil + } id := ID(d).String() return &id } // Ref returns a reference. func (d WidgetID) Ref() *WidgetID { + if d.IsNil() { + return nil + } d2 := d return &d2 } @@ -90,7 +96,7 @@ func (d WidgetID) Contains(ids []WidgetID) bool { // CopyRef returns a copy of a reference. func (d *WidgetID) CopyRef() *WidgetID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -99,7 +105,7 @@ func (d *WidgetID) CopyRef() *WidgetID { // IDRef returns a reference of a domain id. func (d *WidgetID) IDRef() *ID { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d) @@ -108,7 +114,7 @@ func (d *WidgetID) IDRef() *ID { // StringRef returns a reference of a string representation. func (d *WidgetID) StringRef() *string { - if d == nil { + if d == nil || d.IsNil() { return nil } id := ID(*d).String() From bad7e5c9440da527872e879e212d9ff0221e89ed Mon Sep 17 00:00:00 2001 From: rot1024 Date: Fri, 10 Dec 2021 21:05:38 +0900 Subject: [PATCH 20/55] fix rerror test --- pkg/rerror/error_test.go | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/pkg/rerror/error_test.go b/pkg/rerror/error_test.go index d254338d..5aaa011d 100644 --- a/pkg/rerror/error_test.go +++ b/pkg/rerror/error_test.go @@ -11,43 +11,38 @@ import ( func TestErrInternal(t *testing.T) { werr := errors.New("wrapped") err := ErrInternalBy(werr) - var err2 *ErrInternal - assert.Equal(t, "internal", err.Error()) - assert.True(t, errors.As(err, &err2)) + assert.EqualError(t, err, "internal") + assert.IsType(t, err, &ErrInternal{}) assert.Same(t, werr, errors.Unwrap(err)) } func TestError(t *testing.T) { werr := errors.New("wrapped") - label := errors.New("label") - var err error = &Error{Label: label, Err: werr} + err := &Error{Label: errors.New("label"), Err: werr} - var err2 *Error - assert.Equal(t, "label: wrapped", err.Error()) - assert.True(t, errors.As(err, &err2)) + assert.EqualError(t, err, "label: wrapped") assert.Same(t, werr, errors.Unwrap(err)) label2 := errors.New("foo") err3 := &Error{Label: label2, Err: err} - assert.Equal(t, "foo.label: wrapped", err3.Error()) + assert.EqualError(t, err3, "foo.label: wrapped") - label3 := errors.New("bar") - err4 := &Error{Label: label3, Err: err3} - assert.Equal(t, "bar.foo.label: wrapped", err4.Error()) + err4 := &Error{Label: errors.New("bar"), Err: err3} + assert.EqualError(t, err4, "bar.foo.label: wrapped") - err5 := Error{ - Label: label, + err5 := &Error{ + Label: errors.New("label"), Err: werr, Hidden: true, } - assert.Equal(t, "label", err5.Error()) + assert.EqualError(t, err5, "label") var nilerr *Error - assert.Equal(t, "", nilerr.Error()) + assert.EqualError(t, nilerr, "") assert.Nil(t, nilerr.Unwrap()) err6 := &Error{Label: errors.New("d"), Err: &Error{Label: errors.New("e"), Err: &Error{Label: errors.New("f"), Err: errors.New("g")}}, Separate: true} - assert.Equal(t, "d: e.f: g", err6.Error()) + assert.EqualError(t, err6, "d: e.f: g") } func TestFrom(t *testing.T) { @@ -61,7 +56,7 @@ func TestFrom(t *testing.T) { func TestFromSep(t *testing.T) { werr := &Error{Label: errors.New("wrapped"), Err: errors.New("wrapped2")} err := FromSep("label", werr) - assert.Equal(t, "label", err.Label.Error()) + assert.EqualError(t, err.Label, "label") assert.Same(t, werr, err.Err) assert.False(t, err.Hidden) assert.True(t, err.Separate) From f5f9512f3b37e64a88cab04524bd0498be787c40 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Fri, 10 Dec 2021 21:06:24 +0900 Subject: [PATCH 21/55] delete schema field in property.Item, delete IDRef method --- .../adapter/gql/gqlmodel/convert_property.go | 10 +- .../github/plugin_registry_test.go | 32 +++-- .../201217193948_add_scene_default_tile.go | 2 +- .../infrastructure/mongo/mongodoc/property.go | 11 +- .../mongo/mongodoc/property_schema.go | 7 +- internal/usecase/interactor/scene.go | 2 +- pkg/layer/decoding/czml.go | 2 +- pkg/layer/decoding/geojson.go | 2 +- pkg/layer/decoding/kml.go | 2 +- pkg/layer/decoding/kml_test.go | 8 +- pkg/layer/decoding/shp.go | 2 +- pkg/layer/initializer.go | 6 +- pkg/layer/layerops/initializer_test.go | 6 +- pkg/plugin/manifest/convert.go | 9 +- pkg/plugin/manifest/convert_test.go | 30 +++-- pkg/plugin/manifest/parser_test.go | 1 - pkg/property/builder.go | 19 +-- pkg/property/builder_test.go | 115 +++++++----------- pkg/property/group.go | 16 +-- pkg/property/group_builder.go | 7 +- pkg/property/group_builder_test.go | 26 +--- pkg/property/group_list.go | 16 +-- pkg/property/group_list_builder.go | 5 +- pkg/property/group_list_builder_test.go | 48 +++----- pkg/property/group_list_test.go | 81 ++++++------ pkg/property/group_test.go | 28 ++--- pkg/property/initializer.go | 20 +-- pkg/property/initializer_test.go | 34 +++--- pkg/property/item.go | 2 - pkg/property/item_builder.go | 3 +- pkg/property/item_test.go | 17 ++- pkg/property/list_test.go | 2 +- pkg/property/merged.go | 4 +- pkg/property/merged_test.go | 16 +-- pkg/property/property.go | 30 ++--- pkg/property/property_test.go | 56 ++++----- pkg/property/schema.go | 7 -- pkg/property/schema_builder_test.go | 6 +- pkg/property/schema_group.go | 22 ---- pkg/property/schema_group_builder.go | 19 ++- pkg/property/schema_group_builder_test.go | 21 +--- pkg/property/schema_group_test.go | 20 +-- pkg/property/schema_test.go | 5 +- pkg/scene/builder/builder_test.go | 42 +++---- 44 files changed, 340 insertions(+), 479 deletions(-) diff --git a/internal/adapter/gql/gqlmodel/convert_property.go b/internal/adapter/gql/gqlmodel/convert_property.go index b1ddc377..a5a23c3c 100644 --- a/internal/adapter/gql/gqlmodel/convert_property.go +++ b/internal/adapter/gql/gqlmodel/convert_property.go @@ -212,7 +212,7 @@ func ToPropertySchema(propertySchema *property.Schema) *PropertySchema { pgroups := propertySchema.Groups().Groups() groups := make([]*PropertySchemaGroup, 0, len(pgroups)) for _, g := range pgroups { - groups = append(groups, ToPropertySchemaGroup(g)) + groups = append(groups, ToPropertySchemaGroup(g, propertySchema.ID())) } return &PropertySchema{ @@ -365,7 +365,7 @@ func ToMergedPropertyField(f *property.MergedField, s id.PropertySchemaID) *Merg } } -func ToPropertySchemaGroup(g *property.SchemaGroup) *PropertySchemaGroup { +func ToPropertySchemaGroup(g *property.SchemaGroup, p property.SchemaID) *PropertySchemaGroup { if g == nil { return nil } @@ -382,7 +382,7 @@ func ToPropertySchemaGroup(g *property.SchemaGroup) *PropertySchemaGroup { } return &PropertySchemaGroup{ SchemaGroupID: g.ID(), - SchemaID: g.Schema(), + SchemaID: p, IsList: g.IsList(), Title: g.Title().StringRef(), Fields: fields, @@ -406,7 +406,7 @@ func ToPropertyGroup(g *property.Group, p *property.Property, gl *property.Group return &PropertyGroup{ ID: g.ID().ID(), - SchemaID: g.Schema(), + SchemaID: p.Schema(), SchemaGroupID: g.SchemaGroup(), Fields: fields, } @@ -425,7 +425,7 @@ func ToPropertyGroupList(g *property.GroupList, p *property.Property) *PropertyG return &PropertyGroupList{ ID: g.ID().ID(), - SchemaID: g.Schema(), + SchemaID: p.Schema(), SchemaGroupID: g.SchemaGroup(), Groups: groups, } diff --git a/internal/infrastructure/github/plugin_registry_test.go b/internal/infrastructure/github/plugin_registry_test.go index 7da6ef6b..1925e6da 100644 --- a/internal/infrastructure/github/plugin_registry_test.go +++ b/internal/infrastructure/github/plugin_registry_test.go @@ -2,7 +2,6 @@ package github import ( "context" - "errors" "testing" "time" @@ -19,8 +18,16 @@ func TestNewPluginRegistry(t *testing.T) { func TestPluginRegistry_FetchMetadata(t *testing.T) { httpmock.Activate() defer httpmock.DeactivateAndReset() - httpmock.RegisterResponder("GET", "https://raw.githubusercontent.com/reearth/plugins/main/plugins.json", - httpmock.NewStringResponder(200, `[{"name": "reearth","description": "Official Plugin", "author": "reearth", "thumbnailUrl": "", "createdAt": "2021-03-16T04:19:57.592Z"}]`)) + + httpmock.RegisterResponder( + "GET", + "https://raw.githubusercontent.com/reearth/plugins/main/plugins.json", + httpmock.NewStringResponder( + 200, + `[{"name": "reearth","description": "Official Plugin", "author": "reearth", "thumbnailUrl": "", "createdAt": "2021-03-16T04:19:57.592Z"}]`, + ), + ) + d := NewPluginRegistry() res, err := d.FetchMetadata(context.Background()) tm, _ := time.Parse(time.RFC3339, "2021-03-16T04:19:57.592Z") @@ -37,15 +44,20 @@ func TestPluginRegistry_FetchMetadata(t *testing.T) { assert.NoError(t, err) // fail: bad request - httpmock.RegisterResponder("GET", "https://raw.githubusercontent.com/reearth/plugins/main/plugins.json", - httpmock.NewStringResponder(400, `mock bad request`)) + httpmock.RegisterResponder( + "GET", + "https://raw.githubusercontent.com/reearth/plugins/main/plugins.json", + httpmock.NewStringResponder(400, `mock bad request`), + ) _, err = d.FetchMetadata(context.Background()) - assert.True(t, errors.As(errors.New("StatusCode=400"), &err)) + assert.EqualError(t, err, "StatusCode=400") // fail: unable to marshal - httpmock.RegisterResponder("GET", "https://raw.githubusercontent.com/reearth/plugins/main/plugins.json", - httpmock.NewStringResponder(200, `{"hoge": "test"}`)) + httpmock.RegisterResponder( + "GET", + "https://raw.githubusercontent.com/reearth/plugins/main/plugins.json", + httpmock.NewStringResponder(200, `{"hoge": "test"}`), + ) _, err = d.FetchMetadata(context.Background()) - assert.True(t, errors.As(errors.New("cannot unmarshal object into Go value of type []*plugin.Metadata"), &err)) - + assert.Error(t, err) } diff --git a/internal/infrastructure/mongo/migration/201217193948_add_scene_default_tile.go b/internal/infrastructure/mongo/migration/201217193948_add_scene_default_tile.go index bf1f160f..435bc560 100644 --- a/internal/infrastructure/mongo/migration/201217193948_add_scene_default_tile.go +++ b/internal/infrastructure/mongo/migration/201217193948_add_scene_default_tile.go @@ -56,7 +56,7 @@ func AddSceneDefaultTile(ctx context.Context, c DBClient) error { if g == nil || g.Count() > 0 { continue } - f := property.NewGroup().NewID().Schema(p.Schema(), id.PropertySchemaGroupID("tiles")).MustBuild() + f := property.NewGroup().NewID().Schema(id.PropertySchemaGroupID("tiles")).MustBuild() g.Add(f, -1) } diff --git a/internal/infrastructure/mongo/mongodoc/property.go b/internal/infrastructure/mongo/mongodoc/property.go index 5975c346..95ae8d57 100644 --- a/internal/infrastructure/mongo/mongodoc/property.go +++ b/internal/infrastructure/mongo/mongodoc/property.go @@ -36,7 +36,6 @@ type PropertyLinkDocument struct { type PropertyItemDocument struct { Type string ID string - Schema string SchemaGroup string Groups []*PropertyItemDocument Fields []*PropertyFieldDocument @@ -150,7 +149,6 @@ func newPropertyItem(f property.Item) *PropertyItemDocument { return &PropertyItemDocument{ Type: t, ID: f.ID().String(), - Schema: f.Schema().String(), SchemaGroup: string(f.SchemaGroup()), Groups: items, Fields: fields, @@ -237,16 +235,11 @@ func toModelPropertyItem(f *PropertyItemDocument) (property.Item, error) { var i property.Item var err error var iid id.PropertyItemID - var sid id.PropertySchemaID iid, err = id.PropertyItemIDFrom(f.ID) if err != nil { return nil, err } - sid, err = id.PropertySchemaIDFrom(f.Schema) - if err != nil { - return nil, err - } gid := id.PropertySchemaGroupID(f.SchemaGroup) if f.Type == typePropertyItemGroup { @@ -257,7 +250,7 @@ func toModelPropertyItem(f *PropertyItemDocument) (property.Item, error) { i, err = property.NewGroup(). ID(iid). - Schema(sid, gid). + Schema(gid). Fields(fields). Build() } else if f.Type == typePropertyItemGroupList { @@ -274,7 +267,7 @@ func toModelPropertyItem(f *PropertyItemDocument) (property.Item, error) { i, err = property.NewGroupList(). ID(iid). - Schema(sid, gid). + Schema(gid). Groups(items). Build() } diff --git a/internal/infrastructure/mongo/mongodoc/property_schema.go b/internal/infrastructure/mongo/mongodoc/property_schema.go index 60115fbe..05b32010 100644 --- a/internal/infrastructure/mongo/mongodoc/property_schema.go +++ b/internal/infrastructure/mongo/mongodoc/property_schema.go @@ -189,7 +189,7 @@ func (doc *PropertySchemaDocument) Model() (*property.Schema, error) { groups := make([]*property.SchemaGroup, 0, len(doc.Groups)) for _, g := range doc.Groups { - g2, err := toModelPropertySchemaGroup(g, pid) + g2, err := toModelPropertySchemaGroup(g) if err != nil { return nil, err } @@ -247,7 +247,7 @@ func newPropertySchemaGroup(p *property.SchemaGroup) *PropertySchemaGroupDocumen } } -func toModelPropertySchemaGroup(d *PropertySchemaGroupDocument, sid id.PropertySchemaID) (*property.SchemaGroup, error) { +func toModelPropertySchemaGroup(d *PropertySchemaGroupDocument) (*property.SchemaGroup, error) { if d == nil { return nil, nil } @@ -263,12 +263,11 @@ func toModelPropertySchemaGroup(d *PropertySchemaGroupDocument, sid id.PropertyS return property.NewSchemaGroup(). ID(id.PropertySchemaGroupID(d.ID)). - Schema(sid). IsList(d.List). Title(d.Title). IsAvailableIf(toModelPropertyCondition(d.IsAvailableIf)). Fields(fields). - Build() + Build(), nil } func ToDocPropertyLinkableFields(l property.LinkableFields) *PropertyLinkableFieldsDocument { diff --git a/internal/usecase/interactor/scene.go b/internal/usecase/interactor/scene.go index aefeff75..44a548eb 100644 --- a/internal/usecase/interactor/scene.go +++ b/internal/usecase/interactor/scene.go @@ -111,7 +111,7 @@ func (i *Scene) Create(ctx context.Context, pid id.ProjectID, operator *usecase. // add default tile tiles := id.PropertySchemaGroupID("tiles") g := p.GetOrCreateGroupList(schema, property.PointItemBySchema(tiles)) - g.Add(property.NewGroup().NewID().Schema(schema.ID(), tiles).MustBuild(), -1) + g.Add(property.NewGroup().NewID().Schema(tiles).MustBuild(), -1) scene, err := scene.New(). ID(sceneID). diff --git a/pkg/layer/decoding/czml.go b/pkg/layer/decoding/czml.go index b17f266b..d7e0e844 100644 --- a/pkg/layer/decoding/czml.go +++ b/pkg/layer/decoding/czml.go @@ -162,7 +162,7 @@ func (d *CZMLDecoder) decodeLayer(t string, coords []float64, style interface{}, NewID(). Name(layerName). Scene(d.sceneId). - Property(p.IDRef()). + Property(p.ID().Ref()). Extension(&ex). Plugin(&id.OfficialPluginID). Build() diff --git a/pkg/layer/decoding/geojson.go b/pkg/layer/decoding/geojson.go index b21ef8ba..70c0f384 100644 --- a/pkg/layer/decoding/geojson.go +++ b/pkg/layer/decoding/geojson.go @@ -240,7 +240,7 @@ func (d *GeoJSONDecoder) decodeLayer() (*layer.Item, *property.Property, error) NewID(). Name(layerName). Scene(d.sceneId). - Property(p.IDRef()). + Property(p.ID().Ref()). Extension(&ex). Plugin(&id.OfficialPluginID). Build() diff --git a/pkg/layer/decoding/kml.go b/pkg/layer/decoding/kml.go index 07f701d8..3018ff89 100644 --- a/pkg/layer/decoding/kml.go +++ b/pkg/layer/decoding/kml.go @@ -241,7 +241,7 @@ func (d *KMLDecoder) decodePlacemark(p kml.Placemark) (*layer.Item, *property.Pr NewID(). Name(layerName). Scene(d.sceneId). - Property(prop.IDRef()). + Property(prop.ID().Ref()). Extension(&ex). Plugin(&id.OfficialPluginID). Build() diff --git a/pkg/layer/decoding/kml_test.go b/pkg/layer/decoding/kml_test.go index 62be12af..23af06d0 100644 --- a/pkg/layer/decoding/kml_test.go +++ b/pkg/layer/decoding/kml_test.go @@ -552,7 +552,7 @@ func TestKMLdecodePlacemark(t *testing.T) { NewID(). Name("Point"). Scene(s). - Property(point.IDRef()). + Property(point.ID().Ref()). Extension(&pointExt). Plugin(&id.OfficialPluginID). MustBuild(), @@ -576,7 +576,7 @@ func TestKMLdecodePlacemark(t *testing.T) { NewID(). Name("Polyline"). Scene(s). - Property(polyline.IDRef()). + Property(polyline.ID().Ref()). Extension(&polylineExt). Plugin(&id.OfficialPluginID). MustBuild(), @@ -607,7 +607,7 @@ func TestKMLdecodePlacemark(t *testing.T) { NewID(). Name("Polygon"). Scene(s). - Property(polygon.IDRef()). + Property(polygon.ID().Ref()). Extension(&polygonExt). Plugin(&id.OfficialPluginID). MustBuild(), @@ -672,7 +672,7 @@ func TestKMLdecodePlacemark(t *testing.T) { // NewID(). // Name("test_placemark"). // Scene(s). -// Property(point.IDRef()). +// Property(point.ID().Ref()). // Extension(&pointExt). // Plugin(&id.OfficialPluginID). // MustBuild() diff --git a/pkg/layer/decoding/shp.go b/pkg/layer/decoding/shp.go index e808ce82..0cb38775 100644 --- a/pkg/layer/decoding/shp.go +++ b/pkg/layer/decoding/shp.go @@ -38,7 +38,7 @@ func (shd *ShapeDecoder) getLayer(t string, coords interface{}) (*layer.Item, *p NewItem(). NewID(). Scene(shd.sceneId). - Property(p.IDRef()). + Property(p.ID().Ref()). Extension(&ex). Plugin(&id.OfficialPluginID). Build() diff --git a/pkg/layer/initializer.go b/pkg/layer/initializer.go index 98aa1b71..aa519335 100644 --- a/pkg/layer/initializer.go +++ b/pkg/layer/initializer.go @@ -118,7 +118,7 @@ func (i *Initializer) Layer(sid id.SceneID) (r InitializerResult, err error) { return } if lp != nil { - pid = lp.IDRef() + pid = lp.ID().Ref() r.Properties = r.Properties.Add(lp) } @@ -228,7 +228,7 @@ func (i *InitializerInfobox) Infobox(scene id.SceneID) (*Infobox, property.Map, return nil, nil, ErrInitializationPropertyWith(err) } if ibp != nil { - ibpid = ibp.IDRef() + ibpid = ibp.ID().Ref() pm = pm.Add(ibp) } } @@ -284,7 +284,7 @@ func (i *InitializerInfoboxField) InfoboxField(scene id.SceneID) (*InfoboxField, return nil, nil, ErrInitializationPropertyWith(err) } if p != nil { - pid = p.IDRef() + pid = p.ID().Ref() } } if pid == nil { diff --git a/pkg/layer/layerops/initializer_test.go b/pkg/layer/layerops/initializer_test.go index d016a31c..67009d66 100644 --- a/pkg/layer/layerops/initializer_test.go +++ b/pkg/layer/layerops/initializer_test.go @@ -1,7 +1,6 @@ package layerops import ( - "errors" "testing" "github.com/reearth/reearth-backend/pkg/i18n" @@ -34,6 +33,7 @@ func TestInitialize(t *testing.T) { Extensions(es). MustBuild() s := id.NewSceneID() + testCases := []struct { name string sceneID *id.SceneID @@ -59,6 +59,7 @@ func TestInitialize(t *testing.T) { err: ErrExtensionTypeMustBePrimitive, }, } + for _, tc := range testCases { tc := tc t.Run(tc.name, func(tt *testing.T) { @@ -70,12 +71,13 @@ func TestInitialize(t *testing.T) { ExtensionID: tc.extID, Name: tc.name, }.Initialize() + if tc.err == nil { assert.NoError(tt, err) assert.NotNil(tt, layerItem) assert.NotNil(tt, property) } else { - assert.True(t, errors.As(err, &tc.err)) + assert.Equal(t, tc.err, err) } }) } diff --git a/pkg/plugin/manifest/convert.go b/pkg/plugin/manifest/convert.go index 2fdeedcc..d1d31b8d 100644 --- a/pkg/plugin/manifest/convert.go +++ b/pkg/plugin/manifest/convert.go @@ -68,7 +68,7 @@ func (i *Root) manifest(sid *id.SceneID) (*Manifest, error) { Author(author). Description(i18n.StringFrom(desc)). RepositoryURL(repository). - Schema(pluginSchema.IDRef()). + Schema(pluginSchema.ID().Ref()). Extensions(extensions). Build() if err != nil { @@ -200,7 +200,7 @@ func (i *PropertySchema) schema(pluginID id.PluginID, idstr string) (*property.S // groups groups := make([]*property.SchemaGroup, 0, len(i.Groups)) for _, d := range i.Groups { - item, err := d.schemaGroup(psid) + item, err := d.schemaGroup() if err != nil { return nil, rerror.From(fmt.Sprintf("item (%s)", d.ID), err) } @@ -244,7 +244,7 @@ func (p *PropertyPointer) pointer() *property.SchemaFieldPointer { } } -func (i PropertySchemaGroup) schemaGroup(sid id.PropertySchemaID) (*property.SchemaGroup, error) { +func (i PropertySchemaGroup) schemaGroup() (*property.SchemaGroup, error) { title := i.Title var representativeField *id.PropertySchemaFieldID if i.RepresentativeField != nil { @@ -263,13 +263,12 @@ func (i PropertySchemaGroup) schemaGroup(sid id.PropertySchemaID) (*property.Sch return property.NewSchemaGroup(). ID(id.PropertySchemaGroupID(i.ID)). - Schema(sid). IsList(i.List). Fields(fields). Title(i18n.StringFrom(title)). RepresentativeField(representativeField). IsAvailableIf(i.AvailableIf.condition()). - Build() + Build(), nil } func (o *PropertyCondition) condition() *property.Condition { diff --git a/pkg/plugin/manifest/convert_test.go b/pkg/plugin/manifest/convert_test.go index b0bc8fa4..96ab0cd3 100644 --- a/pkg/plugin/manifest/convert_test.go +++ b/pkg/plugin/manifest/convert_test.go @@ -504,10 +504,18 @@ func TestSchema(t *testing.T) { Linkable: nil, Version: 0, }, - pid: id.OfficialPluginID, - expected: property.NewSchema().ID(id.MustPropertySchemaID("reearth/marker")).Groups([]*property.SchemaGroup{property.NewSchemaGroup().ID("default").Schema(id.MustPropertySchemaID("reearth/cesium")).Fields([]*property.SchemaField{property.NewSchemaField().ID("location").Type(property.ValueTypeLatLng).MustBuild()}).MustBuild()}).MustBuild(), + pid: id.OfficialPluginID, + expected: property.NewSchema(). + ID(id.MustPropertySchemaID("reearth/marker")). + Groups([]*property.SchemaGroup{ + property.NewSchemaGroup().ID("default").Fields([]*property.SchemaField{ + property.NewSchemaField().ID("location").Type(property.ValueTypeLatLng).MustBuild(), + }).MustBuild(), + }). + MustBuild(), }, } + for _, tc := range testCases { tc := tc t.Run(tc.name, func(tt *testing.T) { @@ -534,7 +542,6 @@ func TestSchemaGroup(t *testing.T) { testCases := []struct { name string psg PropertySchemaGroup - sid id.PropertySchemaID expected *property.SchemaGroup err string }{ @@ -561,8 +568,16 @@ func TestSchemaGroup(t *testing.T) { List: false, Title: "marker", }, - sid: id.MustPropertySchemaID("reearth/cesium"), - expected: property.NewSchemaGroup().ID("default").Title(i18n.StringFrom("marker")).Title(i18n.StringFrom(str)).Schema(id.MustPropertySchemaID("reearth/cesium")).Fields([]*property.SchemaField{property.NewSchemaField().ID("location").Type(property.ValueTypeLatLng).MustBuild()}).MustBuild(), + expected: property.NewSchemaGroup(). + ID("default"). + Title(i18n.StringFrom(str)). + Fields([]*property.SchemaField{ + property.NewSchemaField(). + ID("location"). + Type(property.ValueTypeLatLng). + MustBuild(), + }). + MustBuild(), }, { name: "fail invalid schema field", @@ -587,20 +602,19 @@ func TestSchemaGroup(t *testing.T) { List: false, Title: "marker", }, - sid: id.MustPropertySchemaID("reearth/cesium"), expected: nil, err: "field (location): invalid value type: xx", }, } + for _, tc := range testCases { tc := tc t.Run(tc.name, func(tt *testing.T) { tt.Parallel() - res, err := tc.psg.schemaGroup(tc.sid) + res, err := tc.psg.schemaGroup() if tc.err == "" { assert.Equal(tt, tc.expected.Title().String(), res.Title().String()) assert.Equal(tt, tc.expected.Title(), res.Title()) - assert.Equal(tt, tc.expected.Schema(), res.Schema()) assert.Equal(tt, len(tc.expected.Fields()), len(res.Fields())) if len(res.Fields()) > 0 { exf := res.Fields()[0] diff --git a/pkg/plugin/manifest/parser_test.go b/pkg/plugin/manifest/parser_test.go index 08d9661e..5d6c518c 100644 --- a/pkg/plugin/manifest/parser_test.go +++ b/pkg/plugin/manifest/parser_test.go @@ -33,7 +33,6 @@ var normalExpected = &Manifest{ ExtensionSchema: []*property.Schema{ property.NewSchema().ID(id.MustPropertySchemaID("aaa~1.1.1/hoge")).Groups([]*property.SchemaGroup{ property.NewSchemaGroup().ID(id.PropertySchemaGroupID("default")). - Schema(id.MustPropertySchemaID("aaa~1.1.1/hoge")). RepresentativeField(id.PropertySchemaFieldID("a").Ref()). Fields([]*property.SchemaField{ property.NewSchemaField().ID(id.PropertySchemaFieldID("a")). diff --git a/pkg/property/builder.go b/pkg/property/builder.go index c3915680..23f62139 100644 --- a/pkg/property/builder.go +++ b/pkg/property/builder.go @@ -7,40 +7,30 @@ import ( ) var ( - // ErrInvalidItem _ ErrInvalidItem = errors.New("invalid item") ) -// Builder _ type Builder struct { p *Property } -// New _ func New() *Builder { return &Builder{p: &Property{}} } -// Build _ func (b *Builder) Build() (*Property, error) { - if id.ID(b.p.id).IsNil() { + if b.p.id.IsNil() { return nil, id.ErrInvalidID } - if id.ID(b.p.scene).IsNil() { + if b.p.scene.IsNil() { return nil, ErrInvalidSceneID } if b.p.schema.IsNil() { return nil, ErrInvalidPropertySchemaID } - for _, i := range b.p.items { - if !i.Schema().Equal(b.p.schema) { - return nil, ErrInvalidItem - } - } return b.p, nil } -// MustBuild _ func (b *Builder) MustBuild() *Property { p, err := b.Build() if err != nil { @@ -49,31 +39,26 @@ func (b *Builder) MustBuild() *Property { return p } -// ID _ func (b *Builder) ID(id id.PropertyID) *Builder { b.p.id = id return b } -// NewID _ func (b *Builder) NewID() *Builder { b.p.id = id.PropertyID(id.New()) return b } -// Scene _ func (b *Builder) Scene(s id.SceneID) *Builder { b.p.scene = s return b } -// Schema _ func (b *Builder) Schema(schema id.PropertySchemaID) *Builder { b.p.schema = schema return b } -// Items _ func (b *Builder) Items(items []Item) *Builder { if len(items) == 0 { b.p.items = nil diff --git a/pkg/property/builder_test.go b/pkg/property/builder_test.go index b1f16cc7..acafde86 100644 --- a/pkg/property/builder_test.go +++ b/pkg/property/builder_test.go @@ -1,7 +1,6 @@ package property import ( - "errors" "testing" "github.com/reearth/reearth-backend/pkg/id" @@ -37,7 +36,6 @@ func TestBuilder_Scene(t *testing.T) { func TestBuilder_Items(t *testing.T) { iid := id.NewPropertyItemID() - propertySchemaID := id.MustPropertySchemaID("xxx~1.1.1/aa") propertySchemaField1ID := id.PropertySchemaFieldID("a") propertySchemaGroup1ID := id.PropertySchemaGroupID("A") @@ -53,14 +51,14 @@ func TestBuilder_Items(t *testing.T) { { Name: "has duplicated item", Input: []Item{ - NewGroup().ID(iid).Schema(propertySchemaID, propertySchemaGroup1ID). + NewGroup().ID(iid).Schema(propertySchemaGroup1ID). Fields([]*Field{ NewField(). Field(propertySchemaField1ID). Value(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). Build(), }).MustBuild(), - NewGroup().ID(iid).Schema(propertySchemaID, propertySchemaGroup1ID). + NewGroup().ID(iid).Schema(propertySchemaGroup1ID). Fields([]*Field{ NewField(). Field(propertySchemaField1ID). @@ -68,7 +66,7 @@ func TestBuilder_Items(t *testing.T) { Build(), }).MustBuild(), }, - Expected: []Item{NewGroup().ID(iid).Schema(propertySchemaID, propertySchemaGroup1ID). + Expected: []Item{NewGroup().ID(iid).Schema(propertySchemaGroup1ID). Fields([]*Field{ NewField(). Field(propertySchemaField1ID). @@ -93,51 +91,41 @@ func TestBuilder_Items(t *testing.T) { } func TestBuilder_Build(t *testing.T) { - pid := id.NewPropertyID() sid := id.NewSceneID() - scid := id.MustPropertySchemaID("xxx~1.1.1/aa") - iid := id.NewPropertyItemID() - propertySchemaField1ID := id.PropertySchemaFieldID("a") - propertySchemaGroup1ID := id.PropertySchemaGroupID("A") + psid := MustSchemaID("test~1.0.0/a") + pid := NewID() + iid := NewItemID() + propertySchemaField1ID := FieldID("a") + propertySchemaGroup1ID := SchemaGroupID("A") - testCases := []struct { + tests := []struct { Name string - Id id.PropertyID + ID ID Scene id.SceneID - Schema id.PropertySchemaID + Schema SchemaID Items []Item Err error - Expected struct { - Id id.PropertyID - Scene id.SceneID - Schema id.PropertySchemaID - Items []Item - } + Expected *Property }{ { Name: "success", - Id: pid, + ID: pid, Scene: sid, - Schema: scid, + Schema: psid, Items: []Item{ - NewGroup().ID(iid).Schema(scid, propertySchemaGroup1ID). + NewGroup().ID(iid).Schema(propertySchemaGroup1ID). Fields([]*Field{ NewField(). Field(propertySchemaField1ID). Value(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). Build(), }).MustBuild()}, - Expected: struct { - Id id.PropertyID - Scene id.SceneID - Schema id.PropertySchemaID - Items []Item - }{ - Id: pid, - Scene: sid, - Schema: scid, - Items: []Item{ - NewGroup().ID(iid).Schema(scid, propertySchemaGroup1ID). + Expected: &Property{ + id: pid, + scene: sid, + schema: psid, + items: []Item{ + NewGroup().ID(iid).Schema(propertySchemaGroup1ID). Fields([]*Field{ NewField(). Field(propertySchemaField1ID). @@ -147,53 +135,40 @@ func TestBuilder_Build(t *testing.T) { }, }, { - Name: "fail invalid id", - Id: id.PropertyID{}, - Items: nil, - Err: id.ErrInvalidID, - }, - { - Name: "fail invalid scene", - Id: pid, - Items: nil, - Err: ErrInvalidSceneID, + Name: "fail invalid id", + ID: id.PropertyID{}, + Scene: sid, + Schema: psid, + Items: nil, + Err: id.ErrInvalidID, }, { - Name: "fail invalid schema", - Id: pid, - Scene: sid, - Items: nil, - Err: ErrInvalidPropertySchemaID, + Name: "fail invalid scene", + ID: pid, + Scene: id.SceneID{}, + Schema: psid, + Items: nil, + Err: ErrInvalidSceneID, }, { - Name: "fail invalid item", - Id: pid, + Name: "fail invalid schema", + ID: pid, Scene: sid, - Schema: scid, - Items: []Item{ - NewGroup().ID(iid).Schema(id.MustPropertySchemaID("zzz~1.1.1/aa"), propertySchemaGroup1ID). - Fields([]*Field{ - NewField(). - Field(propertySchemaField1ID). - Value(OptionalValueFrom(ValueTypeString.ValueFrom("xxx"))). - Build(), - }).MustBuild()}, - Err: ErrInvalidItem, + Schema: SchemaID{}, + Items: nil, + Err: ErrInvalidPropertySchemaID, }, } - for _, tc := range testCases { + for _, tc := range tests { tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - res, err := New().ID(tc.Id).Items(tc.Items).Scene(tc.Scene).Schema(tc.Schema).Build() - if err == nil { - assert.Equal(tt, tc.Expected.Id, res.ID()) - assert.Equal(tt, tc.Expected.Schema, res.Schema()) - assert.Equal(tt, tc.Expected.Items, res.Items()) - assert.Equal(tt, tc.Expected.Scene, res.Scene()) + t.Run(tc.Name, func(t *testing.T) { + t.Parallel() + res, err := New().ID(tc.ID).Schema(tc.Schema).Items(tc.Items).Scene(tc.Scene).Build() + if tc.Err == nil { + assert.Equal(t, tc.Expected, res) } else { - assert.True(tt, errors.As(tc.Err, &err)) + assert.Equal(t, tc.Err, err) } }) } diff --git a/pkg/property/group.go b/pkg/property/group.go index c604f6f6..6fb92569 100644 --- a/pkg/property/group.go +++ b/pkg/property/group.go @@ -31,13 +31,6 @@ func (g *Group) SchemaGroup() id.PropertySchemaGroupID { return g.itemBase.SchemaGroup } -func (g *Group) Schema() id.PropertySchemaID { - if g == nil { - return id.PropertySchemaID{} - } - return g.itemBase.Schema -} - func (g *Group) HasLinkedField() bool { if g == nil { return false @@ -116,8 +109,6 @@ func (g *Group) MigrateSchema(ctx context.Context, newSchema *Schema, dl dataset return } - g.itemBase.Schema = newSchema.ID() - for _, f := range g.fields { if !f.MigrateSchema(ctx, newSchema, dl) { g.RemoveField(f.Field()) @@ -128,7 +119,7 @@ func (g *Group) MigrateSchema(ctx context.Context, newSchema *Schema, dl dataset } func (g *Group) GetOrCreateField(ps *Schema, fid id.PropertySchemaFieldID) (*Field, bool) { - if g == nil || ps == nil || !g.Schema().Equal(ps.ID()) { + if g == nil || ps == nil { return nil, false } psg := ps.Groups().Group(g.SchemaGroup()) @@ -206,7 +197,7 @@ func (g *Group) Field(fid id.PropertySchemaFieldID) *Field { } func (g *Group) UpdateNameFieldValue(ps *Schema, value *Value) error { - if g == nil || ps == nil || !g.Schema().Equal(ps.ID()) { + if g == nil || ps == nil { return nil } if psg := ps.Groups().Group(g.itemBase.SchemaGroup); psg != nil { @@ -226,9 +217,6 @@ func (p *Group) ValidateSchema(ps *SchemaGroup) error { if ps == nil { return errors.New("invalid schema") } - if !p.Schema().Equal(ps.Schema()) { - return errors.New("invalid schema id") - } if p.SchemaGroup() != ps.ID() { return errors.New("invalid schema group id") } diff --git a/pkg/property/group_builder.go b/pkg/property/group_builder.go index d80d12aa..e4622bcf 100644 --- a/pkg/property/group_builder.go +++ b/pkg/property/group_builder.go @@ -16,12 +16,12 @@ func InitGroupFrom(g *SchemaGroup) *Group { if g == nil { return nil } - g2, _ := NewGroup().NewID().Schema(g.Schema(), g.ID()).Build() + g2, _ := NewGroup().NewID().Schema(g.ID()).Build() return g2 } func (b *GroupBuilder) Build() (*Group, error) { - if id.ID(b.p.itemBase.ID).IsNil() { + if b.p.itemBase.ID.IsNil() { return nil, id.ErrInvalidID } return b.p, nil @@ -50,8 +50,7 @@ func (b *GroupBuilder) NewID() *GroupBuilder { return b } -func (b *GroupBuilder) Schema(s id.PropertySchemaID, g id.PropertySchemaGroupID) *GroupBuilder { - b.p.itemBase.Schema = s +func (b *GroupBuilder) Schema(g id.PropertySchemaGroupID) *GroupBuilder { b.p.itemBase.SchemaGroup = g return b } diff --git a/pkg/property/group_builder_test.go b/pkg/property/group_builder_test.go index 091ffc2b..55802380 100644 --- a/pkg/property/group_builder_test.go +++ b/pkg/property/group_builder_test.go @@ -22,7 +22,6 @@ func TestGroupBuilder_Build(t *testing.T) { Fields []*Field Expected struct { Id id.PropertyItemID - Schema id.PropertySchemaID SchemaGroup id.PropertySchemaGroupID Fields []*Field } @@ -40,12 +39,10 @@ func TestGroupBuilder_Build(t *testing.T) { Fields: []*Field{f}, Expected: struct { Id id.PropertyItemID - Schema id.PropertySchemaID SchemaGroup id.PropertySchemaGroupID Fields []*Field }{ Id: iid, - Schema: sid, SchemaGroup: "a", Fields: []*Field{f}, }, @@ -57,10 +54,9 @@ func TestGroupBuilder_Build(t *testing.T) { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() - res, err := NewGroup().ID(tc.Id).Fields(tc.Fields).Schema(tc.Schema, tc.SchemaGroup).Build() + res, err := NewGroup().ID(tc.Id).Fields(tc.Fields).Schema(tc.SchemaGroup).Build() if err == nil { assert.Equal(tt, tc.Expected.Fields, res.Fields(nil)) - assert.Equal(tt, tc.Expected.Schema, res.Schema()) assert.Equal(tt, tc.Expected.SchemaGroup, res.SchemaGroup()) assert.Equal(tt, tc.Expected.Id, res.ID()) } else { @@ -72,7 +68,6 @@ func TestGroupBuilder_Build(t *testing.T) { func TestGroupBuilder_MustBuild(t *testing.T) { iid := id.NewPropertyItemID() - sid := id.MustPropertySchemaID("xx~1.0.0/aa") v := ValueTypeString.ValueFrom("vvv") f := NewField().Field("a").Value(OptionalValueFrom(v)).Build() @@ -85,7 +80,6 @@ func TestGroupBuilder_MustBuild(t *testing.T) { Fields []*Field Expected struct { Id id.PropertyItemID - Schema id.PropertySchemaID SchemaGroup id.PropertySchemaGroupID Fields []*Field } @@ -97,17 +91,14 @@ func TestGroupBuilder_MustBuild(t *testing.T) { { Name: "success", Id: iid, - Schema: sid, SchemaGroup: "a", Fields: []*Field{f}, Expected: struct { Id id.PropertyItemID - Schema id.PropertySchemaID SchemaGroup id.PropertySchemaGroupID Fields []*Field }{ Id: iid, - Schema: sid, SchemaGroup: "a", Fields: []*Field{f}, }, @@ -120,16 +111,12 @@ func TestGroupBuilder_MustBuild(t *testing.T) { tt.Parallel() var res *Group if tc.Fail { - defer func() { - if r := recover(); r != nil { - assert.Nil(tt, res) - } - }() - res = NewGroup().ID(tc.Id).Fields(tc.Fields).Schema(tc.Schema, tc.SchemaGroup).MustBuild() + assert.Panics(t, func() { + _ = NewGroup().ID(tc.Id).Fields(tc.Fields).Schema(tc.SchemaGroup).MustBuild() + }) } else { - res = NewGroup().ID(tc.Id).Fields(tc.Fields).Schema(tc.Schema, tc.SchemaGroup).MustBuild() + res = NewGroup().ID(tc.Id).Fields(tc.Fields).Schema(tc.SchemaGroup).MustBuild() assert.Equal(tt, tc.Expected.Fields, res.Fields(nil)) - assert.Equal(tt, tc.Expected.Schema, res.Schema()) assert.Equal(tt, tc.Expected.SchemaGroup, res.SchemaGroup()) assert.Equal(tt, tc.Expected.Id, res.ID()) } @@ -146,8 +133,7 @@ func TestGroupBuilder_NewID(t *testing.T) { func TestGroupBuilder_InitGroupFrom(t *testing.T) { var sg *SchemaGroup assert.Nil(t, InitGroupFrom(sg)) - sg = NewSchemaGroup().ID("a").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).MustBuild() + sg = NewSchemaGroup().ID("a").MustBuild() g := InitGroupFrom(sg) assert.Equal(t, sg.ID(), g.SchemaGroup()) - assert.Equal(t, sg.Schema(), g.Schema()) } diff --git a/pkg/property/group_list.go b/pkg/property/group_list.go index ad4f17d0..c14f11c0 100644 --- a/pkg/property/group_list.go +++ b/pkg/property/group_list.go @@ -30,13 +30,6 @@ func (g *GroupList) SchemaGroup() id.PropertySchemaGroupID { return g.itemBase.SchemaGroup } -func (g *GroupList) Schema() id.PropertySchemaID { - if g == nil { - return id.PropertySchemaID{} - } - return g.itemBase.Schema -} - func (g *GroupList) HasLinkedField() bool { if g == nil { return false @@ -103,8 +96,6 @@ func (g *GroupList) MigrateSchema(ctx context.Context, newSchema *Schema, dl dat return } - g.itemBase.Schema = newSchema.ID() - for _, f := range g.groups { f.MigrateSchema(ctx, newSchema, dl) } @@ -278,7 +269,7 @@ func (g *GroupList) Empty() { } func (g *GroupList) GetOrCreateField(ps *Schema, ptr *Pointer) (*Field, bool) { - if g == nil || ptr == nil || ps == nil || ps.ID() != g.Schema() { + if g == nil || ptr == nil || ps == nil { return nil, false } psg := ps.Groups().Group(g.SchemaGroup()) @@ -300,7 +291,7 @@ func (g *GroupList) GetOrCreateField(ps *Schema, ptr *Pointer) (*Field, bool) { } func (g *GroupList) CreateAndAddListItem(ps *Schema, index *int) *Group { - if g == nil || ps == nil || !g.Schema().Equal(ps.ID()) { + if g == nil || ps == nil { return nil } psg := ps.Groups().Group(g.SchemaGroup()) @@ -328,9 +319,6 @@ func (p *GroupList) ValidateSchema(ps *SchemaGroup) error { if ps == nil { return errors.New("invalid schema") } - if !p.Schema().Equal(ps.Schema()) { - return errors.New("invalid schema id") - } if p.SchemaGroup() != ps.ID() { return errors.New("invalid schema group id") } diff --git a/pkg/property/group_list_builder.go b/pkg/property/group_list_builder.go index bebb6a9b..396feda5 100644 --- a/pkg/property/group_list_builder.go +++ b/pkg/property/group_list_builder.go @@ -16,7 +16,7 @@ func InitGroupListFrom(g *SchemaGroup) *GroupList { if g == nil || !g.IsList() { return nil } - g2, _ := NewGroupList().NewID().Schema(g.Schema(), g.ID()).Build() + g2, _ := NewGroupList().NewID().Schema(g.ID()).Build() return g2 } @@ -50,8 +50,7 @@ func (b *GroupListBuilder) NewID() *GroupListBuilder { return b } -func (b *GroupListBuilder) Schema(s id.PropertySchemaID, g id.PropertySchemaGroupID) *GroupListBuilder { - b.p.itemBase.Schema = s +func (b *GroupListBuilder) Schema(g id.PropertySchemaGroupID) *GroupListBuilder { b.p.itemBase.SchemaGroup = g return b } diff --git a/pkg/property/group_list_builder_test.go b/pkg/property/group_list_builder_test.go index 8ef9d7d6..8886c800 100644 --- a/pkg/property/group_list_builder_test.go +++ b/pkg/property/group_list_builder_test.go @@ -20,7 +20,6 @@ func TestGroupListBuilder_Build(t *testing.T) { Groups []*Group Expected struct { Id id.PropertyItemID - Schema id.PropertySchemaID SchemaGroup id.PropertySchemaGroupID Groups []*Group } @@ -34,12 +33,10 @@ func TestGroupListBuilder_Build(t *testing.T) { Groups: groups, Expected: struct { Id id.PropertyItemID - Schema id.PropertySchemaID SchemaGroup id.PropertySchemaGroupID Groups []*Group }{ Id: pid, - Schema: scid, SchemaGroup: "aa", Groups: groups, }, @@ -53,11 +50,10 @@ func TestGroupListBuilder_Build(t *testing.T) { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() - res, err := NewGroupList().ID(tc.Id).Schema(tc.Schema, tc.SchemaGroup).Groups(tc.Groups).Build() + res, err := NewGroupList().ID(tc.Id).Schema(tc.SchemaGroup).Groups(tc.Groups).Build() if err == nil { assert.Equal(tt, tc.Expected.Id, res.ID()) assert.Equal(tt, tc.Expected.SchemaGroup, res.SchemaGroup()) - assert.Equal(tt, tc.Expected.Schema, res.Schema()) assert.Equal(tt, tc.Expected.Groups, res.Groups()) } else { assert.True(tt, errors.As(tc.Err, &err)) @@ -75,7 +71,7 @@ func TestGroupListBuilder_MustBuild(t *testing.T) { pid := id.NewPropertyItemID() scid := id.MustPropertySchemaID("xx~1.0.0/aa") groups := []*Group{NewGroup().ID(pid).MustBuild()} - testCases := []struct { + tests := []struct { Name string Fails bool Id id.PropertyItemID @@ -112,24 +108,19 @@ func TestGroupListBuilder_MustBuild(t *testing.T) { Fails: true, }, } - for _, tc := range testCases { + for _, tc := range tests { tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - var res *GroupList + t.Run(tc.Name, func(t *testing.T) { + t.Parallel() if tc.Fails { - defer func() { - if r := recover(); r != nil { - assert.Nil(tt, res) - } - }() - res = NewGroupList().ID(tc.Id).Schema(tc.Schema, tc.SchemaGroup).Groups(tc.Groups).MustBuild() + assert.Panics(t, func() { + _ = NewGroupList().ID(tc.Id).Schema(tc.SchemaGroup).Groups(tc.Groups).MustBuild() + }) } else { - res = NewGroupList().ID(tc.Id).Schema(tc.Schema, tc.SchemaGroup).Groups(tc.Groups).MustBuild() - assert.Equal(tt, tc.Expected.Id, res.ID()) - assert.Equal(tt, tc.Expected.SchemaGroup, res.SchemaGroup()) - assert.Equal(tt, tc.Expected.Schema, res.Schema()) - assert.Equal(tt, tc.Expected.Groups, res.Groups()) + res := NewGroupList().ID(tc.Id).Schema(tc.SchemaGroup).Groups(tc.Groups).MustBuild() + assert.Equal(t, tc.Expected.Id, res.ID()) + assert.Equal(t, tc.Expected.SchemaGroup, res.SchemaGroup()) + assert.Equal(t, tc.Expected.Groups, res.Groups()) } }) @@ -138,19 +129,17 @@ func TestGroupListBuilder_MustBuild(t *testing.T) { func TestInitGroupListFrom(t *testing.T) { testCases := []struct { - Name string - SchemaGroup *SchemaGroup - ExpectedSG id.PropertySchemaGroupID - ExpectedSchema id.PropertySchemaID + Name string + SchemaGroup *SchemaGroup + ExpectedSG id.PropertySchemaGroupID }{ { Name: "nil schema group", }, { - Name: "success", - SchemaGroup: NewSchemaGroup().ID("aa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).MustBuild(), - ExpectedSG: "aa", - ExpectedSchema: id.MustPropertySchemaID("xx~1.0.0/aa"), + Name: "success", + SchemaGroup: NewSchemaGroup().ID("aa").MustBuild(), + ExpectedSG: "aa", }, } @@ -160,7 +149,6 @@ func TestInitGroupListFrom(t *testing.T) { tt.Parallel() res := InitGroupFrom(tc.SchemaGroup) assert.Equal(tt, tc.ExpectedSG, res.SchemaGroup()) - assert.Equal(tt, tc.ExpectedSchema, res.Schema()) }) } } diff --git a/pkg/property/group_list_test.go b/pkg/property/group_list_test.go index d8fdefdb..49381cd4 100644 --- a/pkg/property/group_list_test.go +++ b/pkg/property/group_list_test.go @@ -9,7 +9,7 @@ import ( ) var ( - testGroupList1 = NewGroupList().NewID().Schema(testSchema1.ID(), testSchemaGroup2.ID()).Groups([]*Group{testGroup2}).MustBuild() + testGroupList1 = NewGroupList().NewID().Schema(testSchemaGroup2.ID()).Groups([]*Group{testGroup2}).MustBuild() ) func TestGroupList_HasLinkedField(t *testing.T) { @@ -30,12 +30,12 @@ func TestGroupList_HasLinkedField(t *testing.T) { }, { Name: "has linked field", - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups).MustBuild(), + GL: NewGroupList().NewID().Schema("xx").Groups(groups).MustBuild(), Expected: true, }, { Name: "no linked field", - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups2).MustBuild(), + GL: NewGroupList().NewID().Schema("xx").Groups(groups2).MustBuild(), Expected: false, }, } @@ -68,12 +68,12 @@ func TestGroupList_Datasets(t *testing.T) { }, { Name: "one dataset", - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups(groups).MustBuild(), Expected: []id.DatasetID{dsid}, }, { Name: "empty list", - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups2).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups(groups2).MustBuild(), Expected: []id.DatasetID{}, }, } @@ -106,12 +106,12 @@ func TestGroupList_FieldsByLinkedDataset(t *testing.T) { }, { Name: "one field list", - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups(groups).MustBuild(), Expected: []*Field{f}, }, { Name: "empty list", - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups2).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups(groups2).MustBuild(), Expected: []*Field{}, }, } @@ -143,12 +143,12 @@ func TestGroupList_IsEmpty(t *testing.T) { }, { Name: "is empty", - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").MustBuild(), + Target: NewGroupList().NewID().Schema("xx").MustBuild(), Expected: true, }, { Name: "is not empty", - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups(groups).MustBuild(), Expected: false, }, } @@ -179,7 +179,7 @@ func TestGroupList_Prune(t *testing.T) { }, { Name: "pruned list", - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups(groups).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups(groups).MustBuild(), Expected: pruned, }, } @@ -210,13 +210,13 @@ func TestGroupList_Group(t *testing.T) { { Name: "found", Input: pid, - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g}).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups([]*Group{g}).MustBuild(), Expected: g, }, { Name: "not found", Input: id.NewPropertyItemID(), - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g}).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups([]*Group{g}).MustBuild(), Expected: nil, }, } @@ -235,7 +235,7 @@ func TestGroupList_GroupByPointer(t *testing.T) { g2 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g3 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g4 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() - gl := NewGroupList().NewID().Schema(testSchema1.ID(), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild() + gl := NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild() tests := []struct { Name string @@ -283,7 +283,7 @@ func TestGroupList_GroupAt(t *testing.T) { g2 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g3 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() g4 := NewGroup().ID(id.NewPropertyItemID()).MustBuild() - gl := NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild() + gl := NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild() tests := []struct { Name string @@ -339,13 +339,13 @@ func TestGroupList_Has(t *testing.T) { { Name: "found", Input: g2.ID(), - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: true, }, { Name: "not found", Input: g3.ID(), - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g2, g4}).MustBuild(), Expected: false, }, } @@ -375,7 +375,7 @@ func TestGroupList_Count(t *testing.T) { }, { Name: "not found", - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: 4, }, } @@ -412,7 +412,7 @@ func TestGroupList_Add(t *testing.T) { Name: "index < 0", Index: -1, Gr: g2, - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g3, g4}).MustBuild(), + GL: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g3, g4}).MustBuild(), Expected: struct { Gr *Group Index int @@ -425,7 +425,7 @@ func TestGroupList_Add(t *testing.T) { Name: "len(g) > index > 0 ", Index: 2, Gr: g2, - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g3, g4}).MustBuild(), + GL: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g3, g4}).MustBuild(), Expected: struct { Gr *Group Index int @@ -469,7 +469,7 @@ func TestGroupList_AddOrMove(t *testing.T) { Name: "index < 0", Index: -1, Gr: g2, - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g3, g4}).MustBuild(), + GL: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g3, g4}).MustBuild(), Expected: struct { Gr *Group Index int @@ -482,7 +482,7 @@ func TestGroupList_AddOrMove(t *testing.T) { Name: "len(g) > index > 0 ", Index: 2, Gr: g2, - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g3, g4}).MustBuild(), + GL: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g3, g4}).MustBuild(), Expected: struct { Gr *Group Index int @@ -495,7 +495,7 @@ func TestGroupList_AddOrMove(t *testing.T) { Name: "move group", Index: 2, Gr: g1, - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g3, g4}).MustBuild(), + GL: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g3, g4}).MustBuild(), Expected: struct { Gr *Group Index int @@ -539,7 +539,7 @@ func TestGroupList_Move(t *testing.T) { Name: "success", Id: g1.ID(), ToIndex: 2, - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: struct { Id id.PropertyItemID Index int @@ -576,21 +576,21 @@ func TestGroupList_MoveAt(t *testing.T) { Name: "from = to", FromIndex: 2, ToIndex: 2, - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: []*Group{g1, g2, g3, g4}, }, { Name: "from < 0", FromIndex: -1, ToIndex: 2, - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: []*Group{g1, g2, g3, g4}, }, { Name: "success move", FromIndex: 0, ToIndex: 2, - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: []*Group{g2, g3, g1, g4}, }, } @@ -623,19 +623,19 @@ func TestGroupList_RemoveAt(t *testing.T) { { Name: "success", Index: 1, - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: []*Group{g1, g3, g4}, }, { Name: "index < 0", Index: -1, - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: []*Group{g1, g2, g3, g4}, }, { Name: "index > length", Index: 5, - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: []*Group{g1, g2, g3, g4}, }, } @@ -668,13 +668,13 @@ func TestGroupList_Remove(t *testing.T) { { Name: "success", Input: g1.ID(), - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g2, g3, g4}).MustBuild(), Expected: true, }, { Name: "not found", Input: g4.ID(), - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "xx").Groups([]*Group{g1, g2, g3}).MustBuild(), + Target: NewGroupList().NewID().Schema("xx").Groups([]*Group{g1, g2, g3}).MustBuild(), Expected: false, }, } @@ -691,8 +691,8 @@ func TestGroupList_Remove(t *testing.T) { func TestGroupList_GetOrCreateField(t *testing.T) { sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() - sg := NewSchemaGroup().ID("aa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() - g := NewGroup().ID(id.NewPropertyItemID()).Schema(sg.Schema(), sg.ID()).MustBuild() + sg := NewSchemaGroup().ID("aa").Fields([]*SchemaField{sf}).MustBuild() + g := NewGroup().ID(id.NewPropertyItemID()).Schema(sg.ID()).MustBuild() tests := []struct { Name string @@ -706,7 +706,7 @@ func TestGroupList_GetOrCreateField(t *testing.T) { }{ { Name: "success", - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").Groups([]*Group{g}).MustBuild(), + Target: NewGroupList().NewID().Schema("aa").Groups([]*Group{g}).MustBuild(), Schema: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), Ptr: NewPointer(nil, g.ID().Ref(), sf.ID().Ref()), Expected: struct { @@ -719,15 +719,15 @@ func TestGroupList_GetOrCreateField(t *testing.T) { }, { Name: "can't get a group", - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").MustBuild(), + Target: NewGroupList().NewID().Schema("aa").MustBuild(), Schema: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), Ptr: NewPointer(nil, g.ID().Ref(), sf.ID().Ref()), }, { Name: "FieldByItem not ok: sg!=nil", - Target: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").Groups([]*Group{g}).MustBuild(), + Target: NewGroupList().NewID().Schema("aa").Groups([]*Group{g}).MustBuild(), Schema: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), - Ptr: NewPointer(sg.IDRef(), g.ID().Ref(), sf.ID().Ref()), + Ptr: NewPointer(sg.ID().Ref(), g.ID().Ref(), sf.ID().Ref()), }, { Name: "psg == nil", @@ -751,8 +751,8 @@ func TestGroupList_GetOrCreateField(t *testing.T) { func TestGroupList_CreateAndAddListItem(t *testing.T) { getIntRef := func(i int) *int { return &i } sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() - sg := NewSchemaGroup().ID("aa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() - g := NewGroup().ID(id.NewPropertyItemID()).Schema(sg.Schema(), sg.ID()).MustBuild() + sg := NewSchemaGroup().ID("aa").Fields([]*SchemaField{sf}).MustBuild() + g := NewGroup().ID(id.NewPropertyItemID()).Schema(sg.ID()).MustBuild() tests := []struct { Name string @@ -764,7 +764,7 @@ func TestGroupList_CreateAndAddListItem(t *testing.T) { { Name: "success", Index: getIntRef(0), - GL: NewGroupList().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").MustBuild(), + GL: NewGroupList().NewID().Schema("aa").MustBuild(), Schema: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), Expected: g, }, @@ -775,7 +775,6 @@ func TestGroupList_CreateAndAddListItem(t *testing.T) { t.Run(tt.Name, func(t *testing.T) { t.Parallel() res := tt.GL.CreateAndAddListItem(tt.Schema, tt.Index) - assert.Equal(t, tt.Expected.Schema(), res.Schema()) assert.Equal(t, tt.Expected.Fields(nil), res.Fields(nil)) assert.Equal(t, tt.Expected.SchemaGroup(), res.SchemaGroup()) }) diff --git a/pkg/property/group_test.go b/pkg/property/group_test.go index a4d79a56..9aa67e33 100644 --- a/pkg/property/group_test.go +++ b/pkg/property/group_test.go @@ -10,15 +10,15 @@ import ( ) var ( - testGroup1 = NewGroup().NewID().Schema(testSchema1.ID(), testSchemaGroup1.ID()).Fields([]*Field{testField1}).MustBuild() - testGroup2 = NewGroup().NewID().Schema(testSchema1.ID(), testSchemaGroup2.ID()).Fields([]*Field{testField2}).MustBuild() + testGroup1 = NewGroup().NewID().Schema(testSchemaGroup1.ID()).Fields([]*Field{testField1}).MustBuild() + testGroup2 = NewGroup().NewID().Schema(testSchemaGroup2.ID()).Fields([]*Field{testField2}).MustBuild() ) func TestGroup_SchemaGroup(t *testing.T) { var g *Group assert.Equal(t, id.PropertySchemaGroupID(""), g.SchemaGroup()) pfid := id.PropertySchemaGroupID("aa") - g = NewGroup().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), pfid).MustBuild() + g = NewGroup().NewID().Schema(pfid).MustBuild() assert.Equal(t, pfid, g.SchemaGroup()) } @@ -241,7 +241,7 @@ func TestGroup_Prune(t *testing.T) { func TestGroup_GetOrCreateField(t *testing.T) { sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() f := NewField().Field("aa").Value(NewOptionalValue(ValueTypeString, nil)).Build() - sg := NewSchemaGroup().ID("aa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() + sg := NewSchemaGroup().ID("aa").Fields([]*SchemaField{sf}).MustBuild() tests := []struct { Name string @@ -258,16 +258,16 @@ func TestGroup_GetOrCreateField(t *testing.T) { }, { Name: "nil ps", - Group: NewGroup().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").MustBuild(), + Group: NewGroup().NewID().Schema("aa").MustBuild(), }, { Name: "group schema doesn't equal to ps", - Group: NewGroup().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aaa"), "aa").MustBuild(), + Group: NewGroup().NewID().Schema("aa").MustBuild(), PS: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), }, { Name: "create field", - Group: NewGroup().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").MustBuild(), + Group: NewGroup().NewID().Schema("aa").MustBuild(), PS: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), FID: "aa", Expected: struct { @@ -280,7 +280,7 @@ func TestGroup_GetOrCreateField(t *testing.T) { }, { Name: "get field", - Group: NewGroup().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").Fields([]*Field{f}).MustBuild(), + Group: NewGroup().NewID().Schema("aa").Fields([]*Field{f}).MustBuild(), PS: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), FID: "aa", Expected: struct { @@ -409,8 +409,8 @@ func TestGroup_Field(t *testing.T) { func TestGroup_UpdateNameFieldValue(t *testing.T) { sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() - sg := NewSchemaGroup().ID("aa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() - sg2 := NewSchemaGroup().ID("bb").Schema(id.MustPropertySchemaID("xx~1.0.0/bb")).Fields([]*SchemaField{sf}).MustBuild() + sg := NewSchemaGroup().ID("aa").Fields([]*SchemaField{sf}).MustBuild() + sg2 := NewSchemaGroup().ID("bb").Fields([]*SchemaField{sf}).MustBuild() tests := []struct { Name string @@ -426,16 +426,16 @@ func TestGroup_UpdateNameFieldValue(t *testing.T) { }, { Name: "nil ps", - Group: NewGroup().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").MustBuild(), + Group: NewGroup().NewID().Schema("aa").MustBuild(), }, { Name: "group schema doesn't equal to ps", - Group: NewGroup().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aaa"), "aa").MustBuild(), + Group: NewGroup().NewID().Schema("aa").MustBuild(), PS: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), }, { Name: "update value", - Group: NewGroup().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").MustBuild(), + Group: NewGroup().NewID().Schema("aa").MustBuild(), PS: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{sg}).MustBuild(), Value: ValueTypeString.ValueFrom("abc"), FID: "aa", @@ -443,7 +443,7 @@ func TestGroup_UpdateNameFieldValue(t *testing.T) { }, { Name: "invalid property field", - Group: NewGroup().NewID().Schema(id.MustPropertySchemaID("xx~1.0.0/aa"), "aa").MustBuild(), + Group: NewGroup().NewID().Schema("aa").MustBuild(), PS: NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/bb")).Groups([]*SchemaGroup{sg2}).MustBuild(), Value: ValueTypeString.ValueFrom("abc"), FID: "aa", diff --git a/pkg/property/initializer.go b/pkg/property/initializer.go index f352b421..88096c27 100644 --- a/pkg/property/initializer.go +++ b/pkg/property/initializer.go @@ -51,7 +51,7 @@ func (p *Initializer) Property(scene id.SceneID) (*Property, error) { if p.Items != nil { items = make([]Item, 0, len(p.Items)) for _, i := range p.Items { - item, err := i.PropertyItem(p.Schema) + item, err := i.PropertyItem() if err != nil { return nil, err } @@ -127,7 +127,7 @@ func (p *InitializerItem) Clone() *InitializerItem { } } -func (p *InitializerItem) PropertyItem(parent id.PropertySchemaID) (Item, error) { +func (p *InitializerItem) PropertyItem() (Item, error) { if p == nil { return nil, nil } @@ -137,12 +137,12 @@ func (p *InitializerItem) PropertyItem(parent id.PropertySchemaID) (Item, error) i = id.NewPropertyItemID().Ref() } - pi := NewItem().ID(*i).Schema(parent, p.SchemaItem) + pi := NewItem().ID(*i).Schema(p.SchemaItem) if p.Groups != nil { groups := make([]*Group, 0, len(p.Groups)) for _, g := range p.Groups { - g2, err := g.PropertyGroup(parent, p.SchemaItem) + g2, err := g.PropertyGroup(p.SchemaItem) if err != nil { return nil, err } @@ -167,16 +167,16 @@ func (p *InitializerItem) PropertyItem(parent id.PropertySchemaID) (Item, error) return pi.Group().Fields(fields).Build() } -func (p *InitializerItem) PropertyGroupList(parent id.PropertySchemaID) *GroupList { - i, _ := p.PropertyItem(parent) +func (p *InitializerItem) PropertyGroupList() *GroupList { + i, _ := p.PropertyItem() if g := ToGroupList(i); g != nil { return g } return nil } -func (p *InitializerItem) PropertyGroup(parent id.PropertySchemaID) *Group { - i, _ := p.PropertyItem(parent) +func (p *InitializerItem) PropertyGroup() *Group { + i, _ := p.PropertyItem() if g := ToGroup(i); g != nil { return g } @@ -207,7 +207,7 @@ func (p *InitializerGroup) Clone() *InitializerGroup { } } -func (p *InitializerGroup) PropertyGroup(parent id.PropertySchemaID, parentItem id.PropertySchemaGroupID) (*Group, error) { +func (p *InitializerGroup) PropertyGroup(parentItem id.PropertySchemaGroupID) (*Group, error) { if p == nil { return nil, nil } @@ -217,7 +217,7 @@ func (p *InitializerGroup) PropertyGroup(parent id.PropertySchemaID, parentItem i = id.NewPropertyItemID().Ref() } - pi := NewItem().ID(*i).Schema(parent, parentItem) + pi := NewItem().ID(*i).Schema(parentItem) var fields []*Field if p.Fields != nil { diff --git a/pkg/property/initializer_test.go b/pkg/property/initializer_test.go index a916a985..fb0e3a8b 100644 --- a/pkg/property/initializer_test.go +++ b/pkg/property/initializer_test.go @@ -38,7 +38,7 @@ func TestInitializer_Property(t *testing.T) { } expected := New().ID(*initializer.ID).Schema(initializer.Schema).Scene(sid).Items([]Item{ - NewItem().ID(*initializer.Items[0].ID).Schema(initializer.Schema, initializer.Items[0].SchemaItem).Group().MustBuild(), + NewItem().ID(*initializer.Items[0].ID).Schema(initializer.Items[0].SchemaItem).Group().MustBuild(), }).MustBuild() actual, err := initializer.Property(sid) @@ -80,7 +80,7 @@ func TestInitializer_PropertyIncludingEmpty(t *testing.T) { // test case 3: should generates a property normally actual, err = initializer.PropertyIncludingEmpty(sid, psid2) expected = New().ID(actual.ID()).Schema(initializer.Schema).Scene(sid).Items([]Item{ - NewItem().ID(*initializer.Items[0].ID).Schema(initializer.Schema, initializer.Items[0].SchemaItem).Group().MustBuild(), + NewItem().ID(*initializer.Items[0].ID).Schema(initializer.Items[0].SchemaItem).Group().MustBuild(), }).MustBuild() assert.NoError(t, err) assert.Equal(t, expected, actual) @@ -116,26 +116,24 @@ func TestInitializerItem_Clone(t *testing.T) { } func TestInitializerItem_PropertyItem(t *testing.T) { - parent := id.MustPropertySchemaID("reearth/marker") item := &InitializerItem{ ID: id.NewPropertyItemID().Ref(), SchemaItem: id.PropertySchemaGroupID("hoge"), } - expected := NewItem().ID(*item.ID).Schema(parent, item.SchemaItem).Group().MustBuild() + expected := NewItem().ID(*item.ID).Schema(item.SchemaItem).Group().MustBuild() - created, err := item.PropertyItem(parent) + created, err := item.PropertyItem() assert.NoError(t, err) assert.Equal(t, expected, created) item.ID = nil - created, err = item.PropertyItem(parent) + created, err = item.PropertyItem() assert.NoError(t, err) assert.False(t, created.ID().IsNil()) } func TestInitializerItem_PropertyGroup(t *testing.T) { - parent := id.MustPropertySchemaID("reearth/marker") item := &InitializerItem{ ID: id.NewPropertyItemID().Ref(), SchemaItem: id.PropertySchemaGroupID("hoge"), @@ -146,19 +144,18 @@ func TestInitializerItem_PropertyGroup(t *testing.T) { }}, } - expected := NewItem().ID(*item.ID).Schema(parent, item.SchemaItem).Group().Fields([]*Field{ + expected := NewItem().ID(*item.ID).Schema(item.SchemaItem).Group().Fields([]*Field{ NewField().Field(item.Fields[0].Field).Value(NewOptionalValue(item.Fields[0].Type, item.Fields[0].Value)).Build(), }).MustBuild() - assert.Equal(t, expected, item.PropertyGroup(parent)) + assert.Equal(t, expected, item.PropertyGroup()) // check if a new id is generated item.ID = nil - assert.False(t, item.PropertyGroup(parent).ID().IsNil()) + assert.False(t, item.PropertyGroup().ID().IsNil()) } func TestInitializerItem_PropertyGroupList(t *testing.T) { - parent := id.MustPropertySchemaID("reearth/marker") item := &InitializerItem{ ID: id.NewPropertyItemID().Ref(), SchemaItem: id.PropertySchemaGroupID("hoge"), @@ -167,15 +164,15 @@ func TestInitializerItem_PropertyGroupList(t *testing.T) { }}, } - expected := NewItem().ID(*item.ID).Schema(parent, item.SchemaItem).GroupList().Groups([]*Group{ - NewItem().ID(*item.Groups[0].ID).Schema(parent, item.SchemaItem).Group().MustBuild(), + expected := NewItem().ID(*item.ID).Schema(item.SchemaItem).GroupList().Groups([]*Group{ + NewItem().ID(*item.Groups[0].ID).Schema(item.SchemaItem).Group().MustBuild(), }).MustBuild() - assert.Equal(t, expected, item.PropertyGroupList(parent)) + assert.Equal(t, expected, item.PropertyGroupList()) // check if a new id is generated item.ID = nil - assert.False(t, item.PropertyGroupList(parent).ID().IsNil()) + assert.False(t, item.PropertyGroupList().ID().IsNil()) } func TestInitializerGroup_Clone(t *testing.T) { @@ -202,7 +199,6 @@ func TestInitializerGroup_Clone(t *testing.T) { } func TestInitializerGroup_PropertyGroup(t *testing.T) { - parent := id.MustPropertySchemaID("reearth/marker") parentItem := id.PropertySchemaGroupID("hoge") item := &InitializerGroup{ ID: id.NewPropertyItemID().Ref(), @@ -213,17 +209,17 @@ func TestInitializerGroup_PropertyGroup(t *testing.T) { }}, } - expected := NewItem().ID(*item.ID).Schema(parent, parentItem).Group().Fields([]*Field{ + expected := NewItem().ID(*item.ID).Schema(parentItem).Group().Fields([]*Field{ NewField().Field(item.Fields[0].Field).Value(NewOptionalValue(item.Fields[0].Type, item.Fields[0].Value)).Build(), }).MustBuild() - p, err := item.PropertyGroup(parent, parentItem) + p, err := item.PropertyGroup(parentItem) assert.NoError(t, err) assert.Equal(t, expected, p) // check if a new id is generated item.ID = nil - p, err = item.PropertyGroup(parent, parentItem) + p, err = item.PropertyGroup(parentItem) assert.NoError(t, err) assert.False(t, p.ID().IsNil()) } diff --git a/pkg/property/item.go b/pkg/property/item.go index 3bee4461..64b8422e 100644 --- a/pkg/property/item.go +++ b/pkg/property/item.go @@ -10,7 +10,6 @@ import ( type Item interface { ID() id.PropertyItemID SchemaGroup() id.PropertySchemaGroupID - Schema() id.PropertySchemaID FieldsByLinkedDataset(id.DatasetSchemaID, id.DatasetID) []*Field HasLinkedField() bool Datasets() []id.DatasetID @@ -26,7 +25,6 @@ type Item interface { type itemBase struct { ID id.PropertyItemID - Schema id.PropertySchemaID SchemaGroup id.PropertySchemaGroupID } diff --git a/pkg/property/item_builder.go b/pkg/property/item_builder.go index 67c8d21e..f1673453 100644 --- a/pkg/property/item_builder.go +++ b/pkg/property/item_builder.go @@ -28,8 +28,7 @@ func (b *ItemBuilder) NewID() *ItemBuilder { return b } -func (b *ItemBuilder) Schema(s id.PropertySchemaID, g id.PropertySchemaGroupID) *ItemBuilder { - b.base.Schema = s +func (b *ItemBuilder) Schema(g id.PropertySchemaGroupID) *ItemBuilder { b.base.SchemaGroup = g return b } diff --git a/pkg/property/item_test.go b/pkg/property/item_test.go index 780878dd..0a783872 100644 --- a/pkg/property/item_test.go +++ b/pkg/property/item_test.go @@ -9,11 +9,11 @@ import ( func TestInitItemFrom(t *testing.T) { sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() - sg := NewSchemaGroup().ID("aa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() - sgl := NewSchemaGroup().ID("aa").IsList(true).Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() + sg := NewSchemaGroup().ID("aa").Fields([]*SchemaField{sf}).MustBuild() + sgl := NewSchemaGroup().ID("aa").IsList(true).Fields([]*SchemaField{sf}).MustBuild() iid := id.NewPropertyItemID() - propertySchemaID := id.MustPropertySchemaID("xx~1.0.0/aa") propertySchemaField1ID := id.PropertySchemaGroupID("aa") + testCases := []struct { Name string SG *SchemaGroup @@ -25,12 +25,12 @@ func TestInitItemFrom(t *testing.T) { { Name: "init item from group", SG: sg, - Expected: NewGroup().ID(iid).Schema(propertySchemaID, propertySchemaField1ID).MustBuild(), + Expected: NewGroup().ID(iid).Schema(propertySchemaField1ID).MustBuild(), }, { Name: "init item from group list", SG: sgl, - Expected: NewGroupList().ID(iid).Schema(propertySchemaID, propertySchemaField1ID).MustBuild(), + Expected: NewGroupList().ID(iid).Schema(propertySchemaField1ID).MustBuild(), }, } @@ -40,7 +40,6 @@ func TestInitItemFrom(t *testing.T) { tt.Parallel() res := InitItemFrom(tc.SG) if res != nil { - assert.Equal(tt, tc.Expected.Schema(), res.Schema()) assert.Equal(tt, tc.Expected.SchemaGroup(), res.SchemaGroup()) } else { assert.Nil(tt, tc.Expected) @@ -55,7 +54,7 @@ func TestToGroup(t *testing.T) { propertySchemaField1ID := id.PropertySchemaFieldID("a") propertySchemaGroup1ID := id.PropertySchemaGroupID("A") il := []Item{ - NewGroup().ID(iid).Schema(propertySchemaID, propertySchemaGroup1ID). + NewGroup().ID(iid).Schema(propertySchemaGroup1ID). Fields([]*Field{ NewField(). Field(propertySchemaField1ID). @@ -65,7 +64,6 @@ func TestToGroup(t *testing.T) { } p := New().NewID().Scene(id.NewSceneID()).Items(il).Schema(propertySchemaID).MustBuild() g := ToGroup(p.ItemBySchema(propertySchemaGroup1ID)) - assert.Equal(t, propertySchemaID, g.Schema()) assert.Equal(t, propertySchemaGroup1ID, g.SchemaGroup()) assert.Equal(t, iid, g.ID()) } @@ -75,11 +73,10 @@ func TestToGroupList(t *testing.T) { propertySchemaID := id.MustPropertySchemaID("xxx~1.1.1/aa") propertySchemaGroup1ID := id.PropertySchemaGroupID("A") il := []Item{ - NewGroupList().ID(iid).Schema(propertySchemaID, propertySchemaGroup1ID).MustBuild(), + NewGroupList().ID(iid).Schema(propertySchemaGroup1ID).MustBuild(), } p := New().NewID().Scene(id.NewSceneID()).Items(il).Schema(propertySchemaID).MustBuild() g := ToGroupList(p.ItemBySchema(propertySchemaGroup1ID)) - assert.Equal(t, propertySchemaID, g.Schema()) assert.Equal(t, propertySchemaGroup1ID, g.SchemaGroup()) assert.Equal(t, iid, g.ID()) } diff --git a/pkg/property/list_test.go b/pkg/property/list_test.go index 8b27eadb..e7f20c1e 100644 --- a/pkg/property/list_test.go +++ b/pkg/property/list_test.go @@ -9,7 +9,7 @@ import ( var ( sf = NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() - sg = NewSchemaGroup().ID("aa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() + sg = NewSchemaGroup().ID("aa").Fields([]*SchemaField{sf}).MustBuild() p = New().NewID().Scene(id.NewSceneID()).Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Items([]Item{InitItemFrom(sg)}).MustBuild() p2 = New().NewID().Scene(id.NewSceneID()).Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Items([]Item{InitItemFrom(sg)}).MustBuild() ) diff --git a/pkg/property/merged.go b/pkg/property/merged.go index afe74041..a716e5ed 100644 --- a/pkg/property/merged.go +++ b/pkg/property/merged.go @@ -119,8 +119,8 @@ func Merge(o *Property, p *Property, linked *id.DatasetID) *Merged { } return &Merged{ - Original: o.IDRef(), - Parent: p.IDRef(), + Original: o.ID().Ref(), + Parent: p.ID().Ref(), Schema: schema, Groups: mergeItems(o.Items(), p.Items(), linked2), LinkedDataset: linked2, diff --git a/pkg/property/merged_test.go b/pkg/property/merged_test.go index a6816784..9ed14895 100644 --- a/pkg/property/merged_test.go +++ b/pkg/property/merged_test.go @@ -46,23 +46,23 @@ func TestMerge(t *testing.T) { } groups1 := []*Group{ - NewGroup().ID(i7id).Schema(psid, psgid1).Fields(fields1).MustBuild(), + NewGroup().ID(i7id).Schema(psgid1).Fields(fields1).MustBuild(), } groups2 := []*Group{ - NewGroup().ID(i8id).Schema(psid, psgid1).Fields(fields2).MustBuild(), + NewGroup().ID(i8id).Schema(psgid1).Fields(fields2).MustBuild(), } items1 := []Item{ - NewGroupList().ID(i1id).Schema(psid, psgid1).Groups(groups1).MustBuild(), - NewGroup().ID(i2id).Schema(psid, psgid2).Fields(fields1).MustBuild(), - NewGroup().ID(i3id).Schema(psid, psgid3).Fields(fields1).MustBuild(), + NewGroupList().ID(i1id).Schema(psgid1).Groups(groups1).MustBuild(), + NewGroup().ID(i2id).Schema(psgid2).Fields(fields1).MustBuild(), + NewGroup().ID(i3id).Schema(psgid3).Fields(fields1).MustBuild(), } items2 := []Item{ - NewGroupList().ID(i4id).Schema(psid, psgid1).Groups(groups2).MustBuild(), - NewGroup().ID(i5id).Schema(psid, psgid2).Fields(fields2).MustBuild(), - NewGroup().ID(i6id).Schema(psid, psgid4).Fields(fields2).MustBuild(), + NewGroupList().ID(i4id).Schema(psgid1).Groups(groups2).MustBuild(), + NewGroup().ID(i5id).Schema(psgid2).Fields(fields2).MustBuild(), + NewGroup().ID(i6id).Schema(psgid4).Fields(fields2).MustBuild(), } sid := id.NewSceneID() diff --git a/pkg/property/property.go b/pkg/property/property.go index da36224c..01d44708 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -10,28 +10,30 @@ import ( ) type Property struct { - id id.PropertyID + id ID scene id.SceneID - schema id.PropertySchemaID + schema SchemaID items []Item } -func (p *Property) ID() id.PropertyID { - return p.id -} - -func (p *Property) IDRef() *id.PropertyID { +func (p *Property) ID() ID { if p == nil { - return nil + return ID{} } - return p.id.Ref() + return p.id } func (p *Property) Scene() id.SceneID { + if p == nil { + return id.SceneID{} + } return p.scene } -func (p *Property) Schema() id.PropertySchemaID { +func (p *Property) Schema() SchemaID { + if p == nil { + return SchemaID{} + } return p.schema } @@ -62,7 +64,7 @@ func (p *Property) Items() []Item { return append([]Item{}, p.items...) } -func (p *Property) Item(id id.PropertyItemID) (Item, *GroupList) { +func (p *Property) Item(id ItemID) (Item, *GroupList) { if p == nil { return nil, nil } @@ -80,7 +82,7 @@ func (p *Property) Item(id id.PropertyItemID) (Item, *GroupList) { } // ItemBySchema returns a root item by a schema group ID. -func (p *Property) ItemBySchema(id id.PropertySchemaGroupID) Item { +func (p *Property) ItemBySchema(id SchemaGroupID) Item { if p == nil { return nil } @@ -92,7 +94,7 @@ func (p *Property) ItemBySchema(id id.PropertySchemaGroupID) Item { return nil } -func (p *Property) GroupBySchema(id id.PropertySchemaGroupID) *Group { +func (p *Property) GroupBySchema(id SchemaGroupID) *Group { i := p.ItemBySchema(id) if i == nil { return nil @@ -103,7 +105,7 @@ func (p *Property) GroupBySchema(id id.PropertySchemaGroupID) *Group { return nil } -func (p *Property) GroupListBySchema(id id.PropertySchemaGroupID) *GroupList { +func (p *Property) GroupListBySchema(id SchemaGroupID) *GroupList { i := p.ItemBySchema(id) if i == nil { return nil diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index 7b55424b..675d5f4c 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -16,8 +16,8 @@ var ( func TestPropertyMigrateSchema(t *testing.T) { sceneID := id.NewSceneID() - oldSchema, _ := id.PropertySchemaIDFrom("hoge~1.0.0/test") - newSchema, _ := id.PropertySchemaIDFrom("hoge~1.0.0/test2") + oldSchema := id.MustPropertySchemaID("hoge~1.0.0/test") + newSchema := id.MustPropertySchemaID("hoge~1.0.0/test2") schemaField1ID := id.PropertySchemaFieldID("a") schemaField2ID := id.PropertySchemaFieldID("b") schemaField3ID := id.PropertySchemaFieldID("c") @@ -51,7 +51,7 @@ func TestPropertyMigrateSchema(t *testing.T) { schemaField7, } schemaGroups := []*SchemaGroup{ - NewSchemaGroup().ID(schemaGroupID).Schema(oldSchema).Fields(schemaFields).MustBuild(), + NewSchemaGroup().ID(schemaGroupID).Fields(schemaFields).MustBuild(), } fields := []*Field{ @@ -95,7 +95,7 @@ func TestPropertyMigrateSchema(t *testing.T) { Build(), } items := []Item{ - NewGroup().NewID().Schema(oldSchema, schemaGroupID).Fields(fields).MustBuild(), + NewGroup().NewID().Schema(schemaGroupID).Fields(fields).MustBuild(), } datasetFields := []*dataset.Field{ @@ -113,7 +113,6 @@ func TestPropertyMigrateSchema(t *testing.T) { assert.Equal(t, schema.ID(), property.Schema()) assert.Equal(t, 1, len(property.Items())) - assert.Equal(t, schema.ID(), newGroup.Schema()) assert.Equal(t, 3, len(newFields)) assert.NotNil(t, newGroup.Field(schemaField1ID)) assert.NotNil(t, newGroup.Field(schemaField3ID)) @@ -122,16 +121,16 @@ func TestPropertyMigrateSchema(t *testing.T) { func TestGetOrCreateItem(t *testing.T) { sceneID := id.NewSceneID() - sid, _ := id.PropertySchemaIDFrom("hoge~1.0.0/test") + sid := id.MustPropertySchemaID("hoge~1.0.0/test") sf1id := id.PropertySchemaFieldID("a") sf2id := id.PropertySchemaFieldID("b") sg1id := id.PropertySchemaGroupID("c") sg2id := id.PropertySchemaGroupID("d") sf1 := NewSchemaField().ID(sf1id).Type(ValueTypeString).MustBuild() - sg1 := NewSchemaGroup().ID(sg1id).Schema(sid).Fields([]*SchemaField{sf1}).MustBuild() + sg1 := NewSchemaGroup().ID(sg1id).Fields([]*SchemaField{sf1}).MustBuild() sf2 := NewSchemaField().ID(sf2id).Type(ValueTypeString).MustBuild() - sg2 := NewSchemaGroup().ID(sg2id).Schema(sid).Fields([]*SchemaField{sf2}).IsList(true).MustBuild() + sg2 := NewSchemaGroup().ID(sg2id).Fields([]*SchemaField{sf2}).IsList(true).MustBuild() s := NewSchema().ID(sid).Groups([]*SchemaGroup{sg1, sg2}).MustBuild() p := New().NewID().Scene(sceneID).Schema(sid).MustBuild() @@ -142,7 +141,6 @@ func TestGetOrCreateItem(t *testing.T) { i, _ := p.GetOrCreateItem(s, PointItemBySchema(sg1id)) assert.NotNil(t, i) - assert.Equal(t, sid, i.Schema()) assert.Equal(t, sg1id, i.SchemaGroup()) assert.Equal(t, i, ToGroup(p.ItemBySchema(sg1id))) assert.Equal(t, []Item{i}, p.Items()) @@ -158,7 +156,6 @@ func TestGetOrCreateItem(t *testing.T) { i3, _ := p.GetOrCreateItem(s, PointItemBySchema(sg2id)) assert.NotNil(t, i3) - assert.Equal(t, sid, i3.Schema()) assert.Equal(t, sg2id, i3.SchemaGroup()) assert.Equal(t, i3, ToGroupList(p.ItemBySchema(sg2id))) assert.Equal(t, []Item{i, i3}, p.Items()) @@ -172,16 +169,16 @@ func TestGetOrCreateItem(t *testing.T) { func TestGetOrCreateField(t *testing.T) { sceneID := id.NewSceneID() - sid, _ := id.PropertySchemaIDFrom("hoge~1.0.0/test") + sid := id.MustPropertySchemaID("hoge~1.0.0/test") sf1id := id.PropertySchemaFieldID("a") sf2id := id.PropertySchemaFieldID("b") sg1id := id.PropertySchemaGroupID("c") sg2id := id.PropertySchemaGroupID("d") sf1 := NewSchemaField().ID(sf1id).Type(ValueTypeString).MustBuild() - sg1 := NewSchemaGroup().ID(sg1id).Schema(sid).Fields([]*SchemaField{sf1}).MustBuild() + sg1 := NewSchemaGroup().ID(sg1id).Fields([]*SchemaField{sf1}).MustBuild() sf2 := NewSchemaField().ID(sf2id).Type(ValueTypeString).MustBuild() - sg2 := NewSchemaGroup().ID(sg2id).Schema(sid).Fields([]*SchemaField{sf2}).IsList(true).MustBuild() + sg2 := NewSchemaGroup().ID(sg2id).Fields([]*SchemaField{sf2}).IsList(true).MustBuild() s := NewSchema().ID(sid).Groups([]*SchemaGroup{sg1, sg2}).MustBuild() p := New().NewID().Scene(sceneID).Schema(sid).MustBuild() @@ -195,7 +192,6 @@ func TestGetOrCreateField(t *testing.T) { assert.True(t, created) assert.Equal(t, sf1id, f.Field()) i := ToGroup(p.ItemBySchema(sg1id)) - assert.Equal(t, sid, i.Schema()) assert.Equal(t, sg1id, i.SchemaGroup()) assert.Equal(t, []*Field{f}, i.Fields(nil)) field, _, _ := p.Field(PointFieldBySchemaGroup(sg1id, sf1id)) @@ -224,11 +220,11 @@ func TestGetOrCreateField(t *testing.T) { func TestAddListItem(t *testing.T) { sceneID := id.NewSceneID() - sid, _ := id.PropertySchemaIDFrom("hoge~1.0.0/test") + sid := id.MustPropertySchemaID("hoge~1.0.0/test") sfid := id.PropertySchemaFieldID("a") sgid := id.PropertySchemaGroupID("b") sf := NewSchemaField().ID(sfid).Type(ValueTypeString).MustBuild() - sg := NewSchemaGroup().ID(sgid).Schema(sid).Fields([]*SchemaField{sf}).IsList(true).MustBuild() + sg := NewSchemaGroup().ID(sgid).Fields([]*SchemaField{sf}).IsList(true).MustBuild() ps := NewSchema().ID(sid).Groups([]*SchemaGroup{sg}).MustBuild() p := New().NewID().Scene(sceneID).Schema(sid).MustBuild() @@ -246,11 +242,11 @@ func TestAddListItem(t *testing.T) { func TestMoveListItem(t *testing.T) { sceneID := id.NewSceneID() - sid, _ := id.PropertySchemaIDFrom("hoge~1.0.0/test") + sid := id.MustPropertySchemaID("hoge~1.0.0/test") sgid := id.PropertySchemaGroupID("b") - g1 := NewGroup().NewID().Schema(sid, sgid).MustBuild() - g2 := NewGroup().NewID().Schema(sid, sgid).MustBuild() - gl := NewGroupList().NewID().Schema(sid, sgid).Groups([]*Group{g1, g2}).MustBuild() + g1 := NewGroup().NewID().Schema(sgid).MustBuild() + g2 := NewGroup().NewID().Schema(sgid).MustBuild() + gl := NewGroupList().NewID().Schema(sgid).Groups([]*Group{g1, g2}).MustBuild() p := New().NewID().Scene(sceneID).Schema(sid).Items([]Item{gl}).MustBuild() assert.Equal(t, []*Group{g1, g2}, gl.Groups()) @@ -261,11 +257,11 @@ func TestMoveListItem(t *testing.T) { func TestRemoveListItem(t *testing.T) { sceneID := id.NewSceneID() - sid, _ := id.PropertySchemaIDFrom("hoge~1.0.0/test") + sid := id.MustPropertySchemaID("hoge~1.0.0/test") sgid := id.PropertySchemaGroupID("b") - g1 := NewGroup().NewID().Schema(sid, sgid).MustBuild() - g2 := NewGroup().NewID().Schema(sid, sgid).MustBuild() - gl := NewGroupList().NewID().Schema(sid, sgid).Groups([]*Group{g1, g2}).MustBuild() + g1 := NewGroup().NewID().Schema(sgid).MustBuild() + g2 := NewGroup().NewID().Schema(sgid).MustBuild() + gl := NewGroupList().NewID().Schema(sgid).Groups([]*Group{g1, g2}).MustBuild() p := New().NewID().Scene(sceneID).Schema(sid).Items([]Item{gl}).MustBuild() assert.Equal(t, []*Group{g1, g2}, gl.Groups()) @@ -424,19 +420,19 @@ func TestProperty_MoveFields(t *testing.T) { f1 := NewField().Field(FieldID("x")).Value(OptionalValueFrom(ValueTypeString.ValueFrom("aaa"))).Build() f2 := NewField().Field(FieldID("y")).Value(OptionalValueFrom(ValueTypeString.ValueFrom("bbb"))).Build() p := New().NewID().Scene(id.NewSceneID()).Schema(testSchema1.ID()).Items([]Item{ - NewGroup().NewID().Schema(testSchema1.ID(), sg1).Fields([]*Field{ + NewGroup().NewID().Schema(sg1).Fields([]*Field{ f1, }).MustBuild(), - NewGroup().NewID().Schema(testSchema1.ID(), sg2).Fields([]*Field{ + NewGroup().NewID().Schema(sg2).Fields([]*Field{ // empty }).MustBuild(), - NewGroupList().NewID().Schema(testSchema1.ID(), sg3).Groups([]*Group{ - NewGroup().NewID().Schema(testSchema1.ID(), sg3).Fields([]*Field{ + NewGroupList().NewID().Schema(sg3).Groups([]*Group{ + NewGroup().NewID().Schema(sg3).Fields([]*Field{ f2, }).MustBuild(), }).MustBuild(), - NewGroupList().NewID().Schema(testSchema1.ID(), sg4).Groups([]*Group{ - NewGroup().NewID().Schema(testSchema1.ID(), sg4).Fields([]*Field{ + NewGroupList().NewID().Schema(sg4).Groups([]*Group{ + NewGroup().NewID().Schema(sg4).Fields([]*Field{ // empty }).MustBuild(), }).MustBuild(), diff --git a/pkg/property/schema.go b/pkg/property/schema.go index 3ed3afc8..0f8c7527 100644 --- a/pkg/property/schema.go +++ b/pkg/property/schema.go @@ -23,13 +23,6 @@ func (p *Schema) ID() id.PropertySchemaID { return p.id } -func (p *Schema) IDRef() *id.PropertySchemaID { - if p == nil { - return nil - } - return p.id.Ref() -} - func (p *Schema) Version() int { return p.version } diff --git a/pkg/property/schema_builder_test.go b/pkg/property/schema_builder_test.go index 4f124f85..b5798583 100644 --- a/pkg/property/schema_builder_test.go +++ b/pkg/property/schema_builder_test.go @@ -10,7 +10,7 @@ import ( func TestSchemaBuilder_Build(t *testing.T) { sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() - sg := NewSchemaGroup().ID("aaa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() + sg := NewSchemaGroup().ID("aaa").Fields([]*SchemaField{sf}).MustBuild() testCases := []struct { Name string Id id.PropertySchemaID @@ -73,8 +73,8 @@ func TestSchemaBuilder_Build(t *testing.T) { func TestSchemaBuilder_MustBuild(t *testing.T) { sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() - sg := NewSchemaGroup().ID("aaa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() - sg2 := NewSchemaGroup().ID("daa").Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() + sg := NewSchemaGroup().ID("aaa").Fields([]*SchemaField{sf}).MustBuild() + sg2 := NewSchemaGroup().ID("daa").Fields([]*SchemaField{sf}).MustBuild() testCases := []struct { Name string Fails bool diff --git a/pkg/property/schema_group.go b/pkg/property/schema_group.go index 0b95acf5..67fc31e8 100644 --- a/pkg/property/schema_group.go +++ b/pkg/property/schema_group.go @@ -8,7 +8,6 @@ import ( // SchemaGroup represents a group of property that has some fields type SchemaGroup struct { id id.PropertySchemaGroupID - sid id.PropertySchemaID fields []*SchemaField list bool isAvailableIf *Condition @@ -23,27 +22,6 @@ func (s *SchemaGroup) ID() id.PropertySchemaGroupID { return s.id } -func (s *SchemaGroup) IDRef() *id.PropertySchemaGroupID { - if s == nil { - return nil - } - return s.id.Ref() -} - -func (s *SchemaGroup) Schema() id.PropertySchemaID { - if s == nil { - return id.PropertySchemaID{} - } - return s.sid -} - -func (s *SchemaGroup) SchemaRef() *id.PropertySchemaID { - if s == nil { - return nil - } - return &s.sid -} - // Fields returns a slice of fields func (s *SchemaGroup) Fields() []*SchemaField { if s == nil { diff --git a/pkg/property/schema_group_builder.go b/pkg/property/schema_group_builder.go index 1b61fe11..767589ee 100644 --- a/pkg/property/schema_group_builder.go +++ b/pkg/property/schema_group_builder.go @@ -15,17 +15,17 @@ func NewSchemaGroup() *SchemaGroupBuilder { } } -func (b *SchemaGroupBuilder) Build() (*SchemaGroup, error) { - if b.p.sid.IsNil() { - return nil, id.ErrInvalidID +func (b *SchemaGroupBuilder) Build() *SchemaGroup { + if b.p.id == "" { + return nil } - return b.p, nil + return b.p } func (b *SchemaGroupBuilder) MustBuild() *SchemaGroup { - p, err := b.Build() - if err != nil { - panic(err) + p := b.Build() + if p == nil { + panic("invalid property schema group") } return p } @@ -35,11 +35,6 @@ func (b *SchemaGroupBuilder) ID(id id.PropertySchemaGroupID) *SchemaGroupBuilder return b } -func (b *SchemaGroupBuilder) Schema(sid id.PropertySchemaID) *SchemaGroupBuilder { - b.p.sid = sid - return b -} - func (b *SchemaGroupBuilder) Fields(fields []*SchemaField) *SchemaGroupBuilder { newFields := []*SchemaField{} ids := map[id.PropertySchemaFieldID]struct{}{} diff --git a/pkg/property/schema_group_builder_test.go b/pkg/property/schema_group_builder_test.go index 6b88a95b..b32940ec 100644 --- a/pkg/property/schema_group_builder_test.go +++ b/pkg/property/schema_group_builder_test.go @@ -15,7 +15,6 @@ func TestSchemaGroupBuilder_Build(t *testing.T) { type expected struct { ID id.PropertySchemaGroupID - Sid id.PropertySchemaID Fields []*SchemaField List bool IsAvailableIf *Condition @@ -50,7 +49,6 @@ func TestSchemaGroupBuilder_Build(t *testing.T) { Title: i18n.StringFrom("tt"), Expected: expected{ ID: gid, - Sid: sid, Fields: []*SchemaField{sf}, List: true, IsAvailableIf: &Condition{ @@ -73,7 +71,6 @@ func TestSchemaGroupBuilder_Build(t *testing.T) { Title: i18n.StringFrom("tt"), Expected: expected{ ID: gid, - Sid: sid, Fields: []*SchemaField{sf}, List: true, IsAvailableIf: &Condition{ @@ -89,24 +86,18 @@ func TestSchemaGroupBuilder_Build(t *testing.T) { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() - res, err := NewSchemaGroup(). + res := NewSchemaGroup(). ID(tc.ID). - Schema(tc.Sid). Fields(tc.Fields). IsList(tc.List). Title(tc.Title). IsAvailableIf(tc.IsAvailableIf). Build() - if tc.Err == nil { - assert.Equal(tt, tc.Expected.IsAvailableIf, res.IsAvailableIf()) - assert.Equal(tt, tc.Expected.Sid, res.Schema()) - assert.Equal(tt, tc.Expected.ID, res.ID()) - assert.Equal(tt, tc.Expected.Title, res.Title()) - assert.Equal(tt, tc.Expected.List, res.IsList()) - assert.Equal(tt, tc.Expected.Fields, res.Fields()) - } else { - assert.Equal(tt, tc.Err, err) - } + assert.Equal(tt, tc.Expected.IsAvailableIf, res.IsAvailableIf()) + assert.Equal(tt, tc.Expected.ID, res.ID()) + assert.Equal(tt, tc.Expected.Title, res.Title()) + assert.Equal(tt, tc.Expected.List, res.IsList()) + assert.Equal(tt, tc.Expected.Fields, res.Fields()) }) } } diff --git a/pkg/property/schema_group_test.go b/pkg/property/schema_group_test.go index 5347f76b..c5347dfe 100644 --- a/pkg/property/schema_group_test.go +++ b/pkg/property/schema_group_test.go @@ -9,8 +9,8 @@ import ( ) var ( - testSchemaGroup1 = NewSchemaGroup().ID("aa").Schema(testSchemaID).Fields([]*SchemaField{testSchemaField1, testSchemaField2}).MustBuild() - testSchemaGroup2 = NewSchemaGroup().ID("bb").Schema(testSchemaID).Fields([]*SchemaField{testSchemaField3}).IsList(true).MustBuild() + testSchemaGroup1 = NewSchemaGroup().ID("aa").Fields([]*SchemaField{testSchemaField1, testSchemaField2}).MustBuild() + testSchemaGroup2 = NewSchemaGroup().ID("bb").Fields([]*SchemaField{testSchemaField3}).IsList(true).MustBuild() ) func TestSchemaGroup(t *testing.T) { @@ -22,8 +22,6 @@ func TestSchemaGroup(t *testing.T) { Name string G *SchemaGroup Expected struct { - GIDRef *id.PropertySchemaGroupID - SIDRef *id.PropertySchemaID GID id.PropertySchemaGroupID SID id.PropertySchemaID Fields []*SchemaField @@ -37,10 +35,8 @@ func TestSchemaGroup(t *testing.T) { }, { Name: "success", - G: NewSchemaGroup().ID(scid).Schema(sid).Fields([]*SchemaField{sf}).MustBuild(), + G: NewSchemaGroup().ID(scid).Fields([]*SchemaField{sf}).MustBuild(), Expected: struct { - GIDRef *id.PropertySchemaGroupID - SIDRef *id.PropertySchemaID GID id.PropertySchemaGroupID SID id.PropertySchemaID Fields []*SchemaField @@ -48,8 +44,6 @@ func TestSchemaGroup(t *testing.T) { IsAvailableIf *Condition IsList bool }{ - GIDRef: scid.Ref(), - SIDRef: sid.Ref(), GID: scid, SID: sid, Fields: []*SchemaField{sf}, @@ -64,7 +58,6 @@ func TestSchemaGroup(t *testing.T) { tt.Parallel() assert.Equal(tt, tc.Expected.GID, tc.G.ID()) - assert.Equal(tt, tc.Expected.GIDRef, tc.G.IDRef()) assert.Equal(tt, tc.Expected.Fields, tc.G.Fields()) assert.Equal(tt, tc.Expected.IsList, tc.G.IsList()) assert.Equal(tt, tc.Expected.IsAvailableIf, tc.G.IsAvailableIf()) @@ -75,7 +68,6 @@ func TestSchemaGroup(t *testing.T) { func TestSchemaGroup_Field(t *testing.T) { scid := id.PropertySchemaGroupID("aa") - sid := id.MustPropertySchemaID("xx~1.0.0/aa") sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() testCases := []struct { @@ -90,14 +82,14 @@ func TestSchemaGroup_Field(t *testing.T) { }, { Name: "found", - G: NewSchemaGroup().ID(scid).Schema(sid).Fields([]*SchemaField{sf}).MustBuild(), + G: NewSchemaGroup().ID(scid).Fields([]*SchemaField{sf}).MustBuild(), PTR: NewPointer(nil, nil, sf.ID().Ref()), Input: sf.ID(), Expected: sf, }, { Name: "not found", - G: NewSchemaGroup().ID(scid).Schema(sid).Fields([]*SchemaField{sf}).MustBuild(), + G: NewSchemaGroup().ID(scid).Fields([]*SchemaField{sf}).MustBuild(), PTR: NewPointer(nil, nil, id.PropertySchemaFieldID("zz").Ref()), Input: id.PropertySchemaFieldID("zz"), }, @@ -115,7 +107,7 @@ func TestSchemaGroup_Field(t *testing.T) { } func TestSchemaGroup_SetTitle(t *testing.T) { - sg := NewSchemaGroup().ID(id.PropertySchemaGroupID("aa")).Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Fields([]*SchemaField{sf}).MustBuild() + sg := NewSchemaGroup().ID(id.PropertySchemaGroupID("aa")).Fields([]*SchemaField{sf}).MustBuild() sg.SetTitle(i18n.StringFrom("ttt")) assert.Equal(t, i18n.StringFrom("ttt"), sg.Title()) } diff --git a/pkg/property/schema_test.go b/pkg/property/schema_test.go index 7c055dd5..fd3ec8c3 100644 --- a/pkg/property/schema_test.go +++ b/pkg/property/schema_test.go @@ -8,14 +8,13 @@ import ( ) var ( - testSchemaID = id.MustPropertySchemaID("xx~1.0.0/aa") - testSchema1 = NewSchema().ID(testSchemaID).Groups([]*SchemaGroup{testSchemaGroup1, testSchemaGroup2}).MustBuild() + testSchema1 = NewSchema().ID(id.MustPropertySchemaID("xx~1.0.0/aa")).Groups([]*SchemaGroup{testSchemaGroup1, testSchemaGroup2}).MustBuild() ) func TestLinkableField_Validate(t *testing.T) { sid := id.MustPropertySchemaID("xx~1.0.0/aa") sf := NewSchemaField().ID("aa").Type(ValueTypeString).MustBuild() - sg := NewSchemaGroup().ID("aaa").Schema(sid).Fields([]*SchemaField{sf}).MustBuild() + sg := NewSchemaGroup().ID("aaa").Fields([]*SchemaField{sf}).MustBuild() tests := []struct { Name string diff --git a/pkg/scene/builder/builder_test.go b/pkg/scene/builder/builder_test.go index 8a907743..42b8cc49 100644 --- a/pkg/scene/builder/builder_test.go +++ b/pkg/scene/builder/builder_test.go @@ -73,7 +73,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Schema(propertySchemaID). Items([]property.Item{ - property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). + property.NewGroup().NewID().Schema(propertySchemaGroup1ID). Fields([]*property.Field{ property.NewField(). Field(propertySchemaField1ID). @@ -91,7 +91,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Plugin(&pluginID). Extension(&pluginExtension1ID). - Property(layer1p.IDRef()). + Property(layer1p.ID().Ref()). MustBuild() // layer2: normal layer group @@ -100,7 +100,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Schema(propertySchemaID). Items([]property.Item{ - property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). + property.NewGroup().NewID().Schema(propertySchemaGroup1ID). Fields([]*property.Field{ property.NewField(). Field(propertySchemaField1ID). @@ -118,14 +118,14 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Plugin(&pluginID). Extension(&pluginExtension1ID). - Property(layer21p.IDRef()). + Property(layer21p.ID().Ref()). MustBuild() layer2p := property.New(). NewID(). Scene(sceneID). Schema(propertySchemaID). Items([]property.Item{ - property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). + property.NewGroup().NewID().Schema(propertySchemaGroup1ID). Fields([]*property.Field{ property.NewField(). Field(propertySchemaField1ID). @@ -147,7 +147,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Plugin(&pluginID). Extension(&pluginExtension1ID). - Property(layer2p.IDRef()). + Property(layer2p.ID().Ref()). Infobox(layer2ib). Layers(layer.NewIDList([]id.LayerID{layer21.ID()})). MustBuild() @@ -158,7 +158,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Schema(propertySchemaID). Items([]property.Item{ - property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). + property.NewGroup().NewID().Schema(propertySchemaGroup1ID). Fields([]*property.Field{ property.NewField(). Field(propertySchemaField1ID). @@ -180,7 +180,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Plugin(&pluginID). Extension(&pluginExtension1ID). - Property(layer3p.IDRef()). + Property(layer3p.ID().Ref()). Infobox(layer3ib). MustBuild() @@ -190,7 +190,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Schema(propertySchemaID). Items([]property.Item{ - property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). + property.NewGroup().NewID().Schema(propertySchemaGroup1ID). Fields([]*property.Field{ property.NewField(). Field(propertySchemaField2ID). @@ -208,7 +208,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Plugin(&pluginID). Extension(&pluginExtension1ID). - Property(layer41p.IDRef()). + Property(layer41p.ID().Ref()). Infobox(layer41ib). LinkedDataset(&ds3id). MustBuild() @@ -217,7 +217,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Schema(propertySchemaID). Items([]property.Item{ - property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). + property.NewGroup().NewID().Schema(propertySchemaGroup1ID). Fields([]*property.Field{ property.NewField(). Field(propertySchemaField1ID). @@ -242,7 +242,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Plugin(&pluginID). Extension(&pluginExtension1ID). - Property(layer4p.IDRef()). + Property(layer4p.ID().Ref()). Infobox(layer4ib). LinkedDatasetSchema(&dss3id). Layers(layer.NewIDList([]id.LayerID{layer41.ID()})). @@ -254,7 +254,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Schema(propertySchemaID). Items([]property.Item{ - property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). + property.NewGroup().NewID().Schema(propertySchemaGroup1ID). Fields([]*property.Field{ property.NewField(). Field(propertySchemaField1ID). @@ -271,7 +271,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Plugin(&pluginID). Extension(&pluginExtension1ID). - Property(layer51p.IDRef()). + Property(layer51p.ID().Ref()). LinkedDataset(&ds1id). MustBuild() layer5p := property.New(). @@ -279,7 +279,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Schema(propertySchemaID). Items([]property.Item{ - property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID). + property.NewGroup().NewID().Schema(propertySchemaGroup1ID). Fields([]*property.Field{ property.NewField(). Field(propertySchemaField1ID). @@ -307,7 +307,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Plugin(&pluginID). Extension(&pluginExtension1ID). - Property(layer5p.IDRef()). + Property(layer5p.ID().Ref()). LinkedDatasetSchema(&dss1id). Layers(layer.NewIDList([]id.LayerID{layer51.ID()})). MustBuild() @@ -316,15 +316,15 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Schema(propertySchemaID). Items([]property.Item{ - property.NewGroupList().NewID().Schema(propertySchemaID, propertySchemaGroup2ID).Groups([]*property.Group{ - property.NewGroup().ID(propertyItemID1).Schema(propertySchemaID, propertySchemaGroup2ID). + property.NewGroupList().NewID().Schema(propertySchemaGroup2ID).Groups([]*property.Group{ + property.NewGroup().ID(propertyItemID1).Schema(propertySchemaGroup2ID). Fields([]*property.Field{ property.NewField(). Field(propertySchemaField1ID). Value(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("XYZ"))). Build(), }).MustBuild(), - property.NewGroup().ID(propertyItemID2).Schema(propertySchemaID, propertySchemaGroup2ID). + property.NewGroup().ID(propertyItemID2).Schema(propertySchemaGroup2ID). Fields([]*property.Field{ property.NewField(). Field(propertySchemaField1ID). @@ -339,7 +339,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Plugin(&pluginID). Extension(&pluginExtension1ID). - Property(layer6p.IDRef()). + Property(layer6p.ID().Ref()). MustBuild() // root layer @@ -358,7 +358,7 @@ func TestSceneBuilder(t *testing.T) { Scene(sceneID). Schema(propertySchemaID). Items([]property.Item{ - property.NewGroup().NewID().Schema(propertySchemaID, propertySchemaGroup1ID).Fields([]*property.Field{ + property.NewGroup().NewID().Schema(propertySchemaGroup1ID).Fields([]*property.Field{ property.NewField(). Field(propertySchemaField1ID). Value(property.OptionalValueFrom(property.ValueTypeString.ValueFrom("hogehoge"))). From 459fe9c17551f2852fd6e10758e5477c179bdd5e Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 13 Dec 2021 13:02:34 +0900 Subject: [PATCH 22/55] separate SchemaFieldPointer --- pkg/property/schema.go | 5 ----- pkg/property/schema_pointer.go | 10 +++++++++ pkg/property/schema_pointer_test.go | 34 +++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 pkg/property/schema_pointer.go create mode 100644 pkg/property/schema_pointer_test.go diff --git a/pkg/property/schema.go b/pkg/property/schema.go index 0f8c7527..bffe5ff7 100644 --- a/pkg/property/schema.go +++ b/pkg/property/schema.go @@ -9,11 +9,6 @@ type Schema struct { linkable LinkableFields } -type SchemaFieldPointer struct { - SchemaGroup SchemaGroupID - Field FieldID -} - type LinkableFields struct { LatLng *SchemaFieldPointer URL *SchemaFieldPointer diff --git a/pkg/property/schema_pointer.go b/pkg/property/schema_pointer.go new file mode 100644 index 00000000..8c9a913f --- /dev/null +++ b/pkg/property/schema_pointer.go @@ -0,0 +1,10 @@ +package property + +type SchemaFieldPointer struct { + SchemaGroup SchemaGroupID + Field FieldID +} + +func (p SchemaFieldPointer) Pointer() *Pointer { + return PointFieldBySchemaGroup(p.SchemaGroup, p.Field) +} diff --git a/pkg/property/schema_pointer_test.go b/pkg/property/schema_pointer_test.go new file mode 100644 index 00000000..811407c0 --- /dev/null +++ b/pkg/property/schema_pointer_test.go @@ -0,0 +1,34 @@ +package property + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSchemaFieldPointer_Pointer(t *testing.T) { + tests := []struct { + name string + target *SchemaFieldPointer + want *Pointer + }{ + { + name: "ok", + target: &SchemaFieldPointer{ + SchemaGroup: SchemaGroupID("a"), + Field: FieldID("b"), + }, + want: &Pointer{ + schemaGroup: SchemaGroupID("a").Ref(), + item: nil, + field: FieldID("b").Ref(), + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Pointer()) + }) + } +} From e90ad94fd1bb449bdafe28e3761c2af5f2c1f384 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 13 Dec 2021 19:21:24 +0900 Subject: [PATCH 23/55] RemoveFields returns bool --- pkg/property/group.go | 20 ++++---- pkg/property/group_list.go | 14 ++--- pkg/property/group_list_test.go | 76 +++++++++++++++------------- pkg/property/group_test.go | 90 +++++++++++++++++++-------------- pkg/property/item.go | 2 +- pkg/property/property.go | 16 ++++-- pkg/property/property_test.go | 67 +++++++++++++----------- 7 files changed, 163 insertions(+), 122 deletions(-) diff --git a/pkg/property/group.go b/pkg/property/group.go index 6fb92569..6fa3599b 100644 --- a/pkg/property/group.go +++ b/pkg/property/group.go @@ -149,27 +149,26 @@ func (g *Group) GetOrCreateField(ps *Schema, fid id.PropertySchemaFieldID) (*Fie } func (g *Group) AddFields(fields ...*Field) { - if g == nil || fields == nil { + if g == nil { return } for _, f := range fields { - if field := g.Field(f.Field()); field != nil { - g.RemoveField(f.Field()) - } + _ = g.RemoveField(f.Field()) g.fields = append(g.fields, f) } } -func (g *Group) RemoveField(fid id.PropertySchemaFieldID) { +func (g *Group) RemoveField(fid id.PropertySchemaFieldID) (res bool) { if g == nil { return } for i, f := range g.fields { if f.Field() == fid { g.fields = append(g.fields[:i], g.fields[i+1:]...) - return + return true } } + return } func (g *Group) FieldIDs() []id.PropertySchemaFieldID { @@ -264,11 +263,14 @@ func (g *Group) Fields(p *Pointer) []*Field { return append(g.fields[:0:0], g.fields...) } -func (g *Group) RemoveFields(ptr *Pointer) { +func (g *Group) RemoveFields(ptr *Pointer) (res bool) { if g == nil || ptr == nil { - return + return false } if f, ok := ptr.FieldIfItemIs(g.SchemaGroup(), g.ID()); ok { - g.RemoveField(f) + if g.RemoveField(f) { + res = true + } } + return } diff --git a/pkg/property/group_list.go b/pkg/property/group_list.go index c14f11c0..2ab04d43 100644 --- a/pkg/property/group_list.go +++ b/pkg/property/group_list.go @@ -372,24 +372,26 @@ func (g *GroupList) Fields(ptr *Pointer) []*Field { return fields } -func (g *GroupList) RemoveFields(ptr *Pointer) { +func (g *GroupList) RemoveFields(ptr *Pointer) (res bool) { if g == nil { return } if i, ok := ptr.Item(); ok && g.ID() != i { - g.GroupByPointer(ptr).RemoveFields(ptr) - return + return g.GroupByPointer(ptr).RemoveFields(ptr) } if i, ok := ptr.ItemBySchemaGroup(); ok && g.SchemaGroup() != i { - g.GroupByPointer(ptr).RemoveFields(ptr) - return + return g.GroupByPointer(ptr).RemoveFields(ptr) } if fid, ok := ptr.Field(); ok { for _, g := range g.groups { - g.RemoveField(fid) + if g.RemoveField(fid) { + res = true + } } } + + return } diff --git a/pkg/property/group_list_test.go b/pkg/property/group_list_test.go index 49381cd4..2f53be84 100644 --- a/pkg/property/group_list_test.go +++ b/pkg/property/group_list_test.go @@ -893,60 +893,68 @@ func TestGroupList_RemoveFields(t *testing.T) { p *Pointer } tests := []struct { - name string - target *GroupList - args args - want []*Field + name string + target *GroupList + args args + want bool + wantFields []*Field }{ { - name: "nil pointer", - target: testGroupList1.Clone(), - args: args{p: nil}, - want: []*Field{testField2}, + name: "nil pointer", + target: testGroupList1.Clone(), + args: args{p: nil}, + want: false, + wantFields: []*Field{testField2}, }, { - name: "specified", - target: testGroupList1.Clone(), - args: args{p: PointFieldOnly(testField2.Field())}, - want: nil, + name: "specified", + target: testGroupList1.Clone(), + args: args{p: PointFieldOnly(testField2.Field())}, + want: true, + wantFields: nil, }, { - name: "specified schema group", - target: testGroupList1.Clone(), - args: args{p: PointItemBySchema(testGroupList1.SchemaGroup())}, - want: []*Field{testField2}, + name: "specified schema group", + target: testGroupList1.Clone(), + args: args{p: PointItemBySchema(testGroupList1.SchemaGroup())}, + want: false, + wantFields: []*Field{testField2}, }, { - name: "specified item", - target: testGroupList1.Clone(), - args: args{p: PointItem(testGroupList1.ID())}, - want: []*Field{testField2}, + name: "specified item", + target: testGroupList1.Clone(), + args: args{p: PointItem(testGroupList1.ID())}, + want: false, + wantFields: []*Field{testField2}, }, { - name: "not found", - target: testGroupList1.Clone(), - args: args{p: PointFieldOnly("xxxxxx")}, - want: []*Field{testField2}, + name: "not found", + target: testGroupList1.Clone(), + args: args{p: PointFieldOnly("xxxxxx")}, + want: false, + wantFields: []*Field{testField2}, }, { - name: "empty", - target: &GroupList{}, - args: args{p: PointFieldOnly(testField1.Field())}, - want: nil, + name: "empty", + target: &GroupList{}, + args: args{p: PointFieldOnly(testField1.Field())}, + want: false, + wantFields: nil, }, { - name: "nil", - target: nil, - args: args{p: PointFieldOnly(testField1.Field())}, - want: nil, + name: "nil", + target: nil, + args: args{p: PointFieldOnly(testField1.Field())}, + want: false, + wantFields: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - tt.target.RemoveFields(tt.args.p) + assert.Equal(t, tt.want, tt.target.RemoveFields(tt.args.p)) if tt.target != nil { - assert.Equal(t, tt.want, tt.target.Fields(nil)) + assert.Equal(t, tt.wantFields, tt.target.Fields(nil)) } }) } diff --git a/pkg/property/group_test.go b/pkg/property/group_test.go index 9aa67e33..1a408c15 100644 --- a/pkg/property/group_test.go +++ b/pkg/property/group_test.go @@ -307,23 +307,31 @@ func TestGroup_GetOrCreateField(t *testing.T) { func TestGroup_RemoveField(t *testing.T) { v := ValueTypeString.ValueFrom("vvv") f := NewField().Field("a").Value(OptionalValueFrom(v)).Build() - f2 := NewField().Field("b").Build() + f2 := NewField().Field("b").Value(NewOptionalValue(ValueTypeString, nil)).Build() tests := []struct { - Name string - Group *Group - Input id.PropertySchemaFieldID - Expected []*Field + Name string + Target *Group + Input id.PropertySchemaFieldID + Want bool + WantFields []*Field }{ - { Name: "nil group", }, { - Name: "normal case", - Input: "b", - Group: NewGroup().NewID().Fields([]*Field{f, f2}).MustBuild(), - Expected: []*Field{f}, + Name: "normal case", + Input: "b", + Target: NewGroup().NewID().Fields([]*Field{f, f2}).MustBuild(), + Want: true, + WantFields: []*Field{f}, + }, + { + Name: "not found", + Input: "c", + Target: NewGroup().NewID().Fields([]*Field{f, f2}).MustBuild(), + Want: false, + WantFields: []*Field{f, f2}, }, } @@ -331,8 +339,8 @@ func TestGroup_RemoveField(t *testing.T) { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() - tc.Group.RemoveField(tc.Input) - assert.Equal(tt, tc.Expected, tc.Group.Fields(nil)) + assert.Equal(tt, tc.Want, tc.Target.RemoveField(tc.Input)) + assert.Equal(tt, tc.WantFields, tc.Target.Fields(nil)) }) } } @@ -642,48 +650,54 @@ func TestGroup_RemoveFields(t *testing.T) { p *Pointer } tests := []struct { - name string - target *Group - args args - want []*Field + name string + target *Group + args args + want bool + wantFields []*Field }{ { - name: "nil pointer", - target: testGroup1.Clone(), - args: args{p: nil}, - want: []*Field{testField1}, + name: "nil pointer", + target: testGroup1.Clone(), + args: args{p: nil}, + want: false, + wantFields: []*Field{testField1}, }, { - name: "specified", - target: testGroup1.Clone(), - args: args{p: PointFieldOnly(testField1.Field())}, - want: []*Field{}, + name: "specified", + target: testGroup1.Clone(), + args: args{p: PointFieldOnly(testField1.Field())}, + want: true, + wantFields: []*Field{}, }, { - name: "not found", - target: testGroup1.Clone(), - args: args{p: PointFieldOnly("xxxxxx")}, - want: []*Field{testField1}, + name: "not found", + target: testGroup1.Clone(), + args: args{p: PointFieldOnly("xxxxxx")}, + want: false, + wantFields: []*Field{testField1}, }, { - name: "empty", - target: &Group{}, - args: args{p: PointFieldOnly(testField1.Field())}, - want: nil, + name: "empty", + target: &Group{}, + args: args{p: PointFieldOnly(testField1.Field())}, + want: false, + wantFields: nil, }, { - name: "nil", - target: nil, - args: args{p: PointFieldOnly(testField1.Field())}, - want: nil, + name: "nil", + target: nil, + args: args{p: PointFieldOnly(testField1.Field())}, + want: false, + wantFields: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - tt.target.RemoveFields(tt.args.p) + assert.Equal(t, tt.want, tt.target.RemoveFields(tt.args.p)) if tt.target != nil { - assert.Equal(t, tt.want, tt.target.fields) + assert.Equal(t, tt.wantFields, tt.target.fields) } }) } diff --git a/pkg/property/item.go b/pkg/property/item.go index 64b8422e..1ffce8bb 100644 --- a/pkg/property/item.go +++ b/pkg/property/item.go @@ -19,7 +19,7 @@ type Item interface { MigrateSchema(context.Context, *Schema, dataset.Loader) ValidateSchema(*SchemaGroup) error Fields(*Pointer) []*Field - RemoveFields(*Pointer) + RemoveFields(*Pointer) bool CloneItem() Item } diff --git a/pkg/property/property.go b/pkg/property/property.go index 01d44708..89668ed2 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -192,13 +192,16 @@ func (p *Property) Fields(ptr *Pointer) []*Field { return res } -func (p *Property) RemoveFields(ptr *Pointer) { +func (p *Property) RemoveFields(ptr *Pointer) (res bool) { if p == nil { return } for _, g := range p.items { - g.RemoveFields(ptr) + if g.RemoveFields(ptr) { + res = true + } } + return } func (p *Property) FieldsByLinkedDataset(s id.DatasetSchemaID, i id.DatasetID) []*Field { @@ -515,7 +518,7 @@ func (p *Property) ValidateSchema(ps *Schema) error { } // MoveFields moves fields between items. Only fields in Groups can be moved to another Group, fields in GroupLists will simply be deleted. -func (p *Property) MoveFields(f FieldID, from, to SchemaGroupID) { +func (p *Property) MoveFields(f FieldID, from, to SchemaGroupID) (res bool) { if p == nil { return } @@ -532,9 +535,14 @@ func (p *Property) MoveFields(f FieldID, from, to SchemaGroupID) { toGroup := p.GroupBySchema(to) for _, f := range fields { - fromItem.RemoveFields(PointFieldOnly(f.Field())) + if fromItem.RemoveFields(PointFieldOnly(f.Field())) { + res = true + } if toGroup != nil { toGroup.AddFields(f) + res = true } } + + return } diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index 675d5f4c..01ad0f91 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -360,53 +360,60 @@ func TestProperty_RemoveFields(t *testing.T) { p *Pointer } tests := []struct { - name string - args args - target *Property - want []*Field + name string + args args + target *Property + want bool + wantFields []*Field }{ { - name: "nil pointer", - target: testProperty1.Clone(), - args: args{p: nil}, - want: []*Field{testField1, testField2}, + name: "nil pointer", + target: testProperty1.Clone(), + args: args{p: nil}, + want: false, + wantFields: []*Field{testField1, testField2}, }, { - name: "specified", - target: testProperty1.Clone(), - args: args{p: PointFieldOnly(testField1.Field())}, - want: []*Field{testField2}, + name: "specified", + target: testProperty1.Clone(), + args: args{p: PointFieldOnly(testField1.Field())}, + want: true, + wantFields: []*Field{testField2}, }, { - name: "item only", - target: testProperty1.Clone(), - args: args{p: PointItem(testGroupList1.ID())}, - want: []*Field{testField1, testField2}, + name: "item only", + target: testProperty1.Clone(), + args: args{p: PointItem(testGroupList1.ID())}, + want: false, + wantFields: []*Field{testField1, testField2}, }, { - name: "not found", - target: testProperty1.Clone(), - args: args{p: PointFieldOnly("xxxxxx")}, - want: []*Field{testField1, testField2}, + name: "not found", + target: testProperty1.Clone(), + args: args{p: PointFieldOnly("xxxxxx")}, + want: false, + wantFields: []*Field{testField1, testField2}, }, { - name: "empty", - target: &Property{}, - args: args{p: PointFieldOnly(testField1.Field())}, - want: nil, + name: "empty", + target: &Property{}, + args: args{p: PointFieldOnly(testField1.Field())}, + want: false, + wantFields: nil, }, { - name: "nil", - target: nil, - args: args{p: PointFieldOnly(testField1.Field())}, - want: nil, + name: "nil", + target: nil, + args: args{p: PointFieldOnly(testField1.Field())}, + want: false, + wantFields: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - tt.target.RemoveFields(tt.args.p) - assert.Equal(t, tt.want, tt.target.Fields(nil)) + assert.Equal(t, tt.want, tt.target.RemoveFields(tt.args.p)) + assert.Equal(t, tt.wantFields, tt.target.Fields(nil)) }) } } From 4086dd09b0866fc18ddc12e74332ce4f212032ea Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 13 Dec 2021 20:03:20 +0900 Subject: [PATCH 24/55] add GroupAndFields method --- pkg/property/group.go | 14 +++++++++++ pkg/property/group_list.go | 17 ++++++++++++++ pkg/property/group_list_test.go | 38 ++++++++++++++++++++++++++++++ pkg/property/group_test.go | 38 ++++++++++++++++++++++++++++++ pkg/property/item.go | 14 +++++++++++ pkg/property/item_test.go | 39 +++++++++++++++++++++++++++++++ pkg/property/property.go | 11 +++++++++ pkg/property/property_test.go | 41 +++++++++++++++++++++++++++++++++ 8 files changed, 212 insertions(+) diff --git a/pkg/property/group.go b/pkg/property/group.go index 6fa3599b..243a17c0 100644 --- a/pkg/property/group.go +++ b/pkg/property/group.go @@ -274,3 +274,17 @@ func (g *Group) RemoveFields(ptr *Pointer) (res bool) { } return } + +func (p *Group) GroupAndFields() []GroupAndField { + if p == nil || len(p.fields) == 0 { + return nil + } + res := []GroupAndField{} + for _, f := range p.fields { + res = append(res, GroupAndField{ + Group: p, + Field: f, + }) + } + return res +} diff --git a/pkg/property/group_list.go b/pkg/property/group_list.go index 2ab04d43..2df487c5 100644 --- a/pkg/property/group_list.go +++ b/pkg/property/group_list.go @@ -395,3 +395,20 @@ func (g *GroupList) RemoveFields(ptr *Pointer) (res bool) { return } + +func (p *GroupList) GroupAndFields() []GroupAndField { + if p == nil || len(p.groups) == 0 { + return nil + } + res := []GroupAndField{} + for _, g := range p.groups { + for _, r := range g.GroupAndFields() { + res = append(res, GroupAndField{ + ParentGroup: p, + Group: r.Group, + Field: r.Field, + }) + } + } + return res +} diff --git a/pkg/property/group_list_test.go b/pkg/property/group_list_test.go index 2f53be84..26e03885 100644 --- a/pkg/property/group_list_test.go +++ b/pkg/property/group_list_test.go @@ -959,3 +959,41 @@ func TestGroupList_RemoveFields(t *testing.T) { }) } } + +func TestGroupList_GroupAndFields(t *testing.T) { + tests := []struct { + name string + target *GroupList + want []GroupAndField + }{ + { + name: "ok", + target: testGroupList1, + want: []GroupAndField{ + {ParentGroup: testGroupList1, Group: testGroup2, Field: testField2}, + }, + }, + { + name: "empty", + target: &GroupList{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := tt.target.GroupAndFields() + assert.Equal(t, tt.want, res) + for i, r := range res { + assert.Same(t, tt.want[i].Field, r.Field) + assert.Same(t, tt.want[i].Group, r.Group) + assert.Same(t, tt.want[i].ParentGroup, r.ParentGroup) + } + }) + } +} diff --git a/pkg/property/group_test.go b/pkg/property/group_test.go index 1a408c15..3677b71f 100644 --- a/pkg/property/group_test.go +++ b/pkg/property/group_test.go @@ -702,3 +702,41 @@ func TestGroup_RemoveFields(t *testing.T) { }) } } + +func TestGroup_GroupAndFields(t *testing.T) { + tests := []struct { + name string + target *Group + want []GroupAndField + }{ + { + name: "ok", + target: testGroup1, + want: []GroupAndField{ + {Group: testGroup1, Field: testField1}, + }, + }, + { + name: "empty", + target: &Group{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := tt.target.GroupAndFields() + assert.Equal(t, tt.want, res) + for i, r := range res { + assert.Same(t, tt.want[i].Field, r.Field) + assert.Same(t, tt.want[i].Group, r.Group) + assert.Same(t, tt.want[i].ParentGroup, r.ParentGroup) + } + }) + } +} diff --git a/pkg/property/item.go b/pkg/property/item.go index 1ffce8bb..2c782711 100644 --- a/pkg/property/item.go +++ b/pkg/property/item.go @@ -21,6 +21,7 @@ type Item interface { Fields(*Pointer) []*Field RemoveFields(*Pointer) bool CloneItem() Item + GroupAndFields() []GroupAndField } type itemBase struct { @@ -47,3 +48,16 @@ func InitItemFrom(psg *SchemaGroup) Item { } return InitGroupFrom(psg) } + +type GroupAndField struct { + ParentGroup *GroupList + Group *Group + Field *Field +} + +func (f GroupAndField) SchemaFieldPointer() SchemaFieldPointer { + return SchemaFieldPointer{ + SchemaGroup: f.Group.SchemaGroup(), + Field: f.Field.Field(), + } +} diff --git a/pkg/property/item_test.go b/pkg/property/item_test.go index 0a783872..f93f6ecb 100644 --- a/pkg/property/item_test.go +++ b/pkg/property/item_test.go @@ -80,3 +80,42 @@ func TestToGroupList(t *testing.T) { assert.Equal(t, propertySchemaGroup1ID, g.SchemaGroup()) assert.Equal(t, iid, g.ID()) } + +func TestGroupAndField_SchemaFieldPointer(t *testing.T) { + tests := []struct { + name string + target GroupAndField + want SchemaFieldPointer + }{ + { + name: "group", + target: GroupAndField{ + ParentGroup: nil, + Group: testGroup1, + Field: testField1, + }, + want: SchemaFieldPointer{ + SchemaGroup: testGroup1.SchemaGroup(), + Field: testField1.Field(), + }, + }, + { + name: "group list", + target: GroupAndField{ + ParentGroup: testGroupList1, + Group: testGroup2, + Field: testField2, + }, + want: SchemaFieldPointer{ + SchemaGroup: testGroup2.SchemaGroup(), + Field: testField2.Field(), + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.SchemaFieldPointer()) + }) + } +} diff --git a/pkg/property/property.go b/pkg/property/property.go index 89668ed2..638744da 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -546,3 +546,14 @@ func (p *Property) MoveFields(f FieldID, from, to SchemaGroupID) (res bool) { return } + +func (p *Property) GroupAndFields() []GroupAndField { + if p == nil || len(p.items) == 0 { + return nil + } + res := []GroupAndField{} + for _, i := range p.items { + res = append(res, i.GroupAndFields()...) + } + return res +} diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index 01ad0f91..0247f089 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -543,3 +543,44 @@ func TestProperty_MoveFields(t *testing.T) { }) } } + +func TestProperty_GroupAndFields(t *testing.T) { + tests := []struct { + name string + target *Property + want []GroupAndField + }{ + { + name: "ok", + target: testProperty1, + want: []GroupAndField{ + {Group: testGroup1, Field: testField1}, + {ParentGroup: testGroupList1, Group: testGroup2, Field: testField2}, + }, + }, + { + name: "empty", + target: &Property{}, + want: nil, + }, + { + name: "nil", + target: &Property{}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := tt.target.GroupAndFields() + assert.Equal(t, tt.want, res) + for i, r := range res { + assert.Same(t, tt.want[i].Field, r.Field) + assert.Same(t, tt.want[i].Group, r.Group) + if tt.want[i].ParentGroup != nil { + assert.Same(t, tt.want[i].ParentGroup, r.ParentGroup) + } + } + }) + } +} From e2e1b8e692afc8469090e0af6480acad96a35e6d Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 13 Dec 2021 20:15:24 +0900 Subject: [PATCH 25/55] add FieldBySchemaFieldPointer to property.SchemaGroup --- pkg/property/schema_group.go | 7 ++++ pkg/property/schema_group_test.go | 56 +++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/pkg/property/schema_group.go b/pkg/property/schema_group.go index 67fc31e8..4818e64c 100644 --- a/pkg/property/schema_group.go +++ b/pkg/property/schema_group.go @@ -30,6 +30,13 @@ func (s *SchemaGroup) Fields() []*SchemaField { return append([]*SchemaField{}, s.fields...) } +func (s *SchemaGroup) FieldBySchemaFieldPointer(ptr SchemaFieldPointer) *SchemaField { + if s == nil || ptr.SchemaGroup != s.ID() { + return nil + } + return s.Field(ptr.Field) +} + // Field returns a field whose id is specified func (s *SchemaGroup) Field(fid id.PropertySchemaFieldID) *SchemaField { if s == nil { diff --git a/pkg/property/schema_group_test.go b/pkg/property/schema_group_test.go index c5347dfe..081cdab4 100644 --- a/pkg/property/schema_group_test.go +++ b/pkg/property/schema_group_test.go @@ -111,3 +111,59 @@ func TestSchemaGroup_SetTitle(t *testing.T) { sg.SetTitle(i18n.StringFrom("ttt")) assert.Equal(t, i18n.StringFrom("ttt"), sg.Title()) } + +func TestSchemaGroup_FieldBySchemaFieldPointer(t *testing.T) { + tests := []struct { + name string + target *SchemaGroup + args SchemaFieldPointer + want *SchemaField + }{ + { + name: "found", + target: testSchemaGroup1, + args: SchemaFieldPointer{ + SchemaGroup: testSchemaGroup1.ID(), + Field: testSchemaField1.ID(), + }, + want: testSchemaField1, + }, + { + name: "not found", + target: testSchemaGroup1, + args: SchemaFieldPointer{ + SchemaGroup: testSchemaGroup2.ID(), + Field: testSchemaField1.ID(), + }, + want: nil, + }, + { + name: "empty", + target: &SchemaGroup{}, + args: SchemaFieldPointer{ + SchemaGroup: testSchemaGroup1.ID(), + Field: testSchemaField1.ID(), + }, + want: nil, + }, + { + name: "nil", + target: nil, + args: SchemaFieldPointer{ + SchemaGroup: testSchemaGroup1.ID(), + Field: testSchemaField1.ID(), + }, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := tt.target.FieldBySchemaFieldPointer(tt.args) + assert.Equal(t, tt.want, res) + if tt.want != nil { + assert.Same(t, tt.want, res) + } + }) + } +} From 0bc763307a52cc95623d3589f8648093239cc393 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 13 Dec 2021 20:32:43 +0900 Subject: [PATCH 26/55] Add SchemaFieldPointer method to SchemaGroupAndField --- pkg/id/property_schema_field.go | 9 ++- pkg/id/property_schema_group.go | 9 ++- pkg/property/schema_field.go | 23 ++++++- pkg/property/schema_group_list.go | 21 ++++--- pkg/property/schema_group_list_test.go | 87 ++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 16 deletions(-) diff --git a/pkg/id/property_schema_field.go b/pkg/id/property_schema_field.go index aaa986e9..b8b9f6d2 100644 --- a/pkg/id/property_schema_field.go +++ b/pkg/id/property_schema_field.go @@ -3,7 +3,7 @@ package id type PropertySchemaFieldID string func PropertySchemaFieldIDFrom(str *string) *PropertySchemaFieldID { - if str == nil { + if str == nil || *str == "" { return nil } id := PropertySchemaFieldID(*str) @@ -11,12 +11,15 @@ func PropertySchemaFieldIDFrom(str *string) *PropertySchemaFieldID { } func (id PropertySchemaFieldID) Ref() *PropertySchemaFieldID { + if id == "" { + return nil + } id2 := id return &id2 } func (id *PropertySchemaFieldID) CopyRef() *PropertySchemaFieldID { - if id == nil { + if id == nil || *id == "" { return nil } id2 := *id @@ -28,7 +31,7 @@ func (id PropertySchemaFieldID) String() string { } func (id *PropertySchemaFieldID) StringRef() *string { - if id == nil { + if id == nil || *id == "" { return nil } str := string(*id) diff --git a/pkg/id/property_schema_group.go b/pkg/id/property_schema_group.go index d0556e05..cfba5c32 100644 --- a/pkg/id/property_schema_group.go +++ b/pkg/id/property_schema_group.go @@ -3,7 +3,7 @@ package id type PropertySchemaGroupID string func PropertySchemaGroupIDFrom(str *string) *PropertySchemaGroupID { - if str == nil { + if str == nil || *str == "" { return nil } id := PropertySchemaGroupID(*str) @@ -11,12 +11,15 @@ func PropertySchemaGroupIDFrom(str *string) *PropertySchemaGroupID { } func (id PropertySchemaGroupID) Ref() *PropertySchemaGroupID { + if id == "" { + return nil + } id2 := id return &id2 } func (id *PropertySchemaGroupID) CopyRef() *PropertySchemaGroupID { - if id == nil { + if id == nil || *id == "" { return nil } id2 := *id @@ -28,7 +31,7 @@ func (id PropertySchemaGroupID) String() string { } func (id *PropertySchemaGroupID) StringRef() *string { - if id == nil { + if id == nil || *id == "" { return nil } str := string(*id) diff --git a/pkg/property/schema_field.go b/pkg/property/schema_field.go index 402be2b0..83959733 100644 --- a/pkg/property/schema_field.go +++ b/pkg/property/schema_field.go @@ -2,11 +2,10 @@ package property import ( "github.com/reearth/reearth-backend/pkg/i18n" - "github.com/reearth/reearth-backend/pkg/id" ) type SchemaField struct { - id id.PropertySchemaFieldID + id FieldID propertyType ValueType title i18n.String description i18n.String @@ -26,27 +25,45 @@ type SchemaFieldChoice struct { Icon string } -func (p *SchemaField) ID() id.PropertySchemaFieldID { +func (p *SchemaField) ID() FieldID { + if p == nil { + return "" + } return p.id } func (p *SchemaField) Type() ValueType { + if p == nil { + return ValueTypeUnknown + } return p.propertyType } func (p *SchemaField) Title() i18n.String { + if p == nil { + return nil + } return p.title.Copy() } func (p *SchemaField) Description() i18n.String { + if p == nil { + return nil + } return p.description.Copy() } func (p *SchemaField) Prefix() string { + if p == nil { + return "" + } return p.prefix } func (p *SchemaField) Suffix() string { + if p == nil { + return "" + } return p.suffix } diff --git a/pkg/property/schema_group_list.go b/pkg/property/schema_group_list.go index 22a76a52..1e33833a 100644 --- a/pkg/property/schema_group_list.go +++ b/pkg/property/schema_group_list.go @@ -6,11 +6,6 @@ type SchemaGroupList struct { groups []*SchemaGroup } -type SchemaGroupAndField struct { - Group *SchemaGroup - Field *SchemaField -} - func NewSchemaGroupList(p []*SchemaGroup) *SchemaGroupList { sgl := &SchemaGroupList{ groups: append(p[:0:0], p...), @@ -122,13 +117,25 @@ func (s *SchemaGroupList) duplicatedGroups() []SchemaGroupID { return duplicated } +type SchemaGroupAndField struct { + Group *SchemaGroup + Field *SchemaField +} + func (gf SchemaGroupAndField) IsEmpty() bool { return gf.Group == nil && gf.Field == nil } func (gf SchemaGroupAndField) Pointer() *Pointer { - if gf.Group == nil || gf.Field == nil { + if gf.Group == nil && gf.Field == nil { return nil } - return PointFieldBySchemaGroup(gf.Group.ID(), gf.Field.ID()) + return NewPointer(gf.Group.ID().Ref(), nil, gf.Field.ID().Ref()) +} + +func (f SchemaGroupAndField) SchemaFieldPointer() SchemaFieldPointer { + return SchemaFieldPointer{ + SchemaGroup: f.Group.ID(), + Field: f.Field.ID(), + } } diff --git a/pkg/property/schema_group_list_test.go b/pkg/property/schema_group_list_test.go index 059e855f..f656a420 100644 --- a/pkg/property/schema_group_list_test.go +++ b/pkg/property/schema_group_list_test.go @@ -288,3 +288,90 @@ func TestSchemaGroupAndField_IsEmpty(t *testing.T) { }) } } + +func TestSchemaGroupAndField_Pointer(t *testing.T) { + tests := []struct { + name string + target SchemaGroupAndField + want *Pointer + }{ + { + name: "ok", + target: SchemaGroupAndField{ + Group: testSchemaGroup1, + Field: testSchemaField1, + }, + want: &Pointer{ + schemaGroup: testSchemaGroup1.ID().Ref(), + item: nil, + field: testSchemaField1.ID().Ref(), + }, + }, + { + name: "nil group", + target: SchemaGroupAndField{ + Group: nil, + Field: testSchemaField1, + }, + want: &Pointer{ + schemaGroup: nil, + item: nil, + field: testSchemaField1.ID().Ref(), + }, + }, + { + name: "nil field", + target: SchemaGroupAndField{ + Group: testSchemaGroup1, + Field: nil, + }, + want: &Pointer{ + schemaGroup: testSchemaGroup1.ID().Ref(), + item: nil, + field: nil, + }, + }, + { + name: "empty", + target: SchemaGroupAndField{}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Pointer()) + }) + } +} + +func TestSchemaGroupAndField_SchemaFieldPointer(t *testing.T) { + tests := []struct { + name string + target SchemaGroupAndField + want SchemaFieldPointer + }{ + { + name: "ok", + target: SchemaGroupAndField{ + Group: testSchemaGroup1, + Field: testSchemaField1, + }, + want: SchemaFieldPointer{ + SchemaGroup: testSchemaGroup1.ID(), + Field: testSchemaField1.ID(), + }, + }, + { + name: "empty", + target: SchemaGroupAndField{}, + want: SchemaFieldPointer{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.SchemaFieldPointer()) + }) + } +} From e6dbd12266ab9e70d4ec1698669e57e0aa9e76cf Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 13 Dec 2021 20:37:49 +0900 Subject: [PATCH 27/55] fix PluginID.IsNil --- pkg/id/plugin.go | 5 +++++ pkg/id/plugin_test.go | 25 +++++++++++++++++++++++++ pkg/id/property_schema.go | 10 ++++++++-- pkg/plugin/builder.go | 3 +-- pkg/property/schema.go | 12 ++++++++---- 5 files changed, 47 insertions(+), 8 deletions(-) diff --git a/pkg/id/plugin.go b/pkg/id/plugin.go index d13ed808..6e3d5df8 100644 --- a/pkg/id/plugin.go +++ b/pkg/id/plugin.go @@ -105,6 +105,11 @@ func PluginIDFromRef(id *string) *PluginID { return &did } +// IsNil checks if ID is empty or not. +func (d PluginID) IsNil() bool { + return d.name == "" && d.version == "" && d.scene == nil && d.sys == false +} + // Name returns a name. func (d PluginID) Name() string { return d.name diff --git a/pkg/id/plugin_test.go b/pkg/id/plugin_test.go index 49a8b937..bdbf68fc 100644 --- a/pkg/id/plugin_test.go +++ b/pkg/id/plugin_test.go @@ -690,3 +690,28 @@ func TestPluginIDsFrom(t *testing.T) { }) } } + +func TestPluginID_IsNil(t *testing.T) { + tests := []struct { + name string + target PluginID + want bool + }{ + { + name: "present", + target: PluginID{name: "a"}, + want: false, + }, + { + name: "empty", + target: PluginID{}, + want: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.IsNil()) + }) + } +} diff --git a/pkg/id/property_schema.go b/pkg/id/property_schema.go index 6530825b..d9d81ceb 100644 --- a/pkg/id/property_schema.go +++ b/pkg/id/property_schema.go @@ -80,18 +80,24 @@ func (d PropertySchemaID) System() bool { // String returns a string representation. func (d PropertySchemaID) String() string { + if d.IsNil() { + return "" + } return d.plugin.String() + "/" + d.id } // Ref returns a reference. func (d PropertySchemaID) Ref() *PropertySchemaID { + if d.IsNil() { + return nil + } d2 := d return &d2 } // CopyRef returns a copy of a reference. func (d *PropertySchemaID) CopyRef() *PropertySchemaID { - if d == nil { + if d == nil || d.IsNil() { return nil } d2 := *d @@ -100,7 +106,7 @@ func (d *PropertySchemaID) CopyRef() *PropertySchemaID { // IsNil checks if ID is empty or not. func (d PropertySchemaID) IsNil() bool { - return d.plugin == PluginID{} && d.id == "" + return d.plugin.IsNil() && d.id == "" } // Equal returns true if two IDs are equal. diff --git a/pkg/plugin/builder.go b/pkg/plugin/builder.go index 44e45910..5bdb18de 100644 --- a/pkg/plugin/builder.go +++ b/pkg/plugin/builder.go @@ -71,8 +71,7 @@ func (b *Builder) Schema(schema *id.PropertySchemaID) *Builder { if schema == nil { b.p.schema = nil } else { - sid := *schema - b.p.schema = &sid + b.p.schema = schema.CopyRef() } return b } diff --git a/pkg/property/schema.go b/pkg/property/schema.go index bffe5ff7..1ddccb67 100644 --- a/pkg/property/schema.go +++ b/pkg/property/schema.go @@ -1,9 +1,7 @@ package property -import "github.com/reearth/reearth-backend/pkg/id" - type Schema struct { - id id.PropertySchemaID + id SchemaID version int groups *SchemaGroupList linkable LinkableFields @@ -14,11 +12,17 @@ type LinkableFields struct { URL *SchemaFieldPointer } -func (p *Schema) ID() id.PropertySchemaID { +func (p *Schema) ID() SchemaID { + if p == nil { + return SchemaID{} + } return p.id } func (p *Schema) Version() int { + if p == nil { + return 0 + } return p.version } From 7e0123d8258927bb5511cbba99617e861a402565 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 13 Dec 2021 20:52:56 +0900 Subject: [PATCH 28/55] add Cast method to property --- pkg/property/field.go | 9 +++-- pkg/property/field_test.go | 37 +++++++++++-------- pkg/property/property.go | 10 +++++ pkg/property/property_test.go | 69 +++++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 20 deletions(-) diff --git a/pkg/property/field.go b/pkg/property/field.go index c1373242..7aa07a45 100644 --- a/pkg/property/field.go +++ b/pkg/property/field.go @@ -112,12 +112,13 @@ func (p *Field) Update(value *Value, field *SchemaField) error { return nil } -func (p *Field) Cast(t ValueType) { - if p == nil || p.Type() == t { - return +func (p *Field) Cast(t ValueType) bool { + if p.IsEmpty() || p.Type() == t { + return false } p.v = p.v.Cast(t) p.Unlink() + return true } func (p *Field) UpdateUnsafe(value *Value) { @@ -146,7 +147,7 @@ func (p *Field) UpdateField(field id.PropertySchemaFieldID) { } func (p *Field) IsEmpty() bool { - return p != nil && p.Value().IsEmpty() && p.Links().IsEmpty() + return p == nil || (p.v.Value() == nil && p.Links().IsEmpty()) } func (p *Field) MigrateSchema(ctx context.Context, newSchema *Schema, dl dataset.Loader) bool { diff --git a/pkg/property/field_test.go b/pkg/property/field_test.go index 71c091b2..de1d4f2a 100644 --- a/pkg/property/field_test.go +++ b/pkg/property/field_test.go @@ -231,10 +231,11 @@ func TestField_Cast(t *testing.T) { t ValueType } tests := []struct { - name string - target *Field - args args - want *Field + name string + target *Field + args args + want bool + wantField *Field }{ { name: "ok", @@ -244,7 +245,8 @@ func TestField_Cast(t *testing.T) { links: dgp.Clone(), }, args: args{t: ValueTypeNumber}, - want: &Field{ + want: true, + wantField: &Field{ field: FieldID("foobar"), v: OptionalValueFrom(ValueTypeNumber.ValueFrom(-123)), }, @@ -257,29 +259,32 @@ func TestField_Cast(t *testing.T) { links: dgp.Clone(), }, args: args{t: ValueTypeLatLng}, - want: &Field{ + want: true, + wantField: &Field{ field: FieldID("foobar"), v: NewOptionalValue(ValueTypeLatLng, nil), }, }, { - name: "empty", - target: &Field{}, - args: args{t: ValueTypeNumber}, - want: &Field{}, + name: "empty", + target: &Field{}, + args: args{t: ValueTypeNumber}, + want: false, + wantField: &Field{}, }, { - name: "nil", - target: nil, - args: args{t: ValueTypeNumber}, - want: nil, + name: "nil", + target: nil, + args: args{t: ValueTypeNumber}, + want: false, + wantField: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - tt.target.Cast(tt.args.t) - assert.Equal(t, tt.want, tt.target) + assert.Equal(t, tt.want, tt.target.Cast(tt.args.t)) + assert.Equal(t, tt.wantField, tt.target) }) } } diff --git a/pkg/property/property.go b/pkg/property/property.go index 638744da..5c2098b8 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -557,3 +557,13 @@ func (p *Property) GroupAndFields() []GroupAndField { } return res } + +// Cast changes the type of fields that are matches the pointer +func (p *Property) Cast(ptr *Pointer, t ValueType) (res bool) { + for _, f := range p.Fields(ptr) { + if f.Cast(t) { + res = true + } + } + return +} diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index 0247f089..ea102ca5 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -584,3 +584,72 @@ func TestProperty_GroupAndFields(t *testing.T) { }) } } + +func TestProperty_Cast(t *testing.T) { + type args struct { + ptr *Pointer + t ValueType + } + tests := []struct { + name string + target *Property + args args + want bool + }{ + { + name: "ok", + target: testProperty1.Clone(), + args: args{ + ptr: PointFieldOnly(testField2.Field()), + t: ValueTypeLatLngHeight, + }, + want: true, + }, + { + name: "failed to cast", + target: testProperty1.Clone(), + args: args{ + ptr: PointFieldOnly(testField2.Field()), + t: ValueTypeNumber, + }, + want: true, + }, + { + name: "not found", + target: testProperty1.Clone(), + args: args{ + ptr: PointFieldOnly("x"), + t: ValueTypeString, + }, + want: false, + }, + { + name: "empty", + target: &Property{}, + args: args{ + ptr: PointFieldOnly(testField1.Field()), + t: ValueTypeString, + }, + want: false, + }, + { + name: "nil", + target: nil, + args: args{ + ptr: PointFieldOnly(testField1.Field()), + t: ValueTypeString, + }, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Cast(tt.args.ptr, tt.args.t)) + for _, f := range tt.target.Fields(tt.args.ptr) { + assert.Equal(t, tt.args.t, f.Type()) + assert.Nil(t, f.Links()) + } + }) + } +} From 6d86996fffa829d02f703088826c58e0ff0eb1d6 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 13 Dec 2021 21:08:03 +0900 Subject: [PATCH 29/55] property.Prune returns bool --- pkg/property/group.go | 5 +-- pkg/property/group_list.go | 7 +++-- pkg/property/group_list_test.go | 39 ++++++++++++++++-------- pkg/property/group_test.go | 39 +++++++++++++++--------- pkg/property/item.go | 2 +- pkg/property/property.go | 13 +++++--- pkg/property/property_test.go | 54 +++++++++++++++++++++++++++++++++ 7 files changed, 123 insertions(+), 36 deletions(-) diff --git a/pkg/property/group.go b/pkg/property/group.go index 243a17c0..63d99d09 100644 --- a/pkg/property/group.go +++ b/pkg/property/group.go @@ -92,15 +92,16 @@ func (g *Group) IsEmpty() bool { return true } -func (g *Group) Prune() { +func (g *Group) Prune() (res bool) { if g == nil { return } for _, f := range g.fields { if f.IsEmpty() { - g.RemoveField(f.Field()) + res = g.RemoveField(f.Field()) } } + return } // TODO: group migration diff --git a/pkg/property/group_list.go b/pkg/property/group_list.go index 2df487c5..26f44403 100644 --- a/pkg/property/group_list.go +++ b/pkg/property/group_list.go @@ -82,13 +82,16 @@ func (g *GroupList) IsEmpty() bool { return g != nil && (g.groups == nil || len(g.groups) == 0) } -func (g *GroupList) Prune() { +func (g *GroupList) Prune() (res bool) { if g == nil { return } for _, f := range g.groups { - f.Prune() + if f.Prune() { + res = true + } } + return } func (g *GroupList) MigrateSchema(ctx context.Context, newSchema *Schema, dl dataset.Loader) { diff --git a/pkg/property/group_list_test.go b/pkg/property/group_list_test.go index 26e03885..9d978539 100644 --- a/pkg/property/group_list_test.go +++ b/pkg/property/group_list_test.go @@ -164,32 +164,45 @@ func TestGroupList_IsEmpty(t *testing.T) { func TestGroupList_Prune(t *testing.T) { v := ValueTypeString.ValueFrom("vvv") f := NewField().Field("a").Value(OptionalValueFrom(v)).Build() - f2 := NewField().Field("a").Build() + f2 := NewField().Field("b").Value(NewOptionalValue(ValueTypeString, nil)).Build() pid := id.NewPropertyItemID() - groups := []*Group{NewGroup().ID(pid).Fields([]*Field{f, f2}).MustBuild()} - pruned := []*Group{NewGroup().ID(pid).Fields([]*Field{f}).MustBuild()} tests := []struct { - Name string - Target *GroupList - Expected []*Group + name string + target *GroupList + want bool + wantGroups []*Group }{ { - Name: "nil group list", + name: "ok", + target: NewGroupList().NewID().Schema("xx").Groups( + []*Group{NewGroup().ID(pid).Fields([]*Field{f, f2}).MustBuild()}, + ).MustBuild(), + want: true, + wantGroups: []*Group{NewGroup().ID(pid).Fields([]*Field{f}).MustBuild()}, }, { - Name: "pruned list", - Target: NewGroupList().NewID().Schema("xx").Groups(groups).MustBuild(), - Expected: pruned, + name: "no empty fields", + target: NewGroupList().NewID().Schema("xx").Groups( + []*Group{NewGroup().ID(pid).Fields([]*Field{f}).MustBuild()}, + ).MustBuild(), + want: false, + wantGroups: []*Group{NewGroup().ID(pid).Fields([]*Field{f}).MustBuild()}, + }, + { + name: "nil", + target: nil, + want: false, + wantGroups: nil, }, } for _, tt := range tests { tt := tt - t.Run(tt.Name, func(t *testing.T) { + t.Run(tt.name, func(t *testing.T) { t.Parallel() - tt.Target.Prune() - assert.Equal(t, tt.Expected, tt.Target.Groups()) + assert.Equal(t, tt.want, tt.target.Prune()) + assert.Equal(t, tt.wantGroups, tt.target.Groups()) }) } } diff --git a/pkg/property/group_test.go b/pkg/property/group_test.go index 3677b71f..9c9715e9 100644 --- a/pkg/property/group_test.go +++ b/pkg/property/group_test.go @@ -211,29 +211,40 @@ func TestGroup_IsEmpty(t *testing.T) { func TestGroup_Prune(t *testing.T) { v := ValueTypeString.ValueFrom("vvv") f := NewField().Field("a").Value(OptionalValueFrom(v)).Build() - f2 := NewField().Field("a").Build() + f2 := NewField().Field("b").Value(NewOptionalValue(ValueTypeBool, nil)).Build() tests := []struct { - Name string - Group *Group - Expected []*Field + name string + target *Group + want bool + wantFields []*Field }{ { - Name: "nil group", + name: "ok", + target: NewGroup().NewID().Fields([]*Field{f, f2}).MustBuild(), + want: true, + wantFields: []*Field{f}, }, { - Name: "normal case", - Group: NewGroup().NewID().Fields([]*Field{f, f2}).MustBuild(), - Expected: []*Field{f}, + name: "no empty fields", + target: NewGroup().NewID().Fields([]*Field{f}).MustBuild(), + want: false, + wantFields: []*Field{f}, + }, + { + name: "nil", + target: nil, + want: false, + wantFields: nil, }, } - for _, tc := range tests { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { - tt.Parallel() - tc.Group.Prune() - assert.Equal(tt, tc.Expected, tc.Group.Fields(nil)) + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.Prune()) + assert.Equal(t, tt.wantFields, tt.target.Fields(nil)) }) } } diff --git a/pkg/property/item.go b/pkg/property/item.go index 2c782711..18b5104a 100644 --- a/pkg/property/item.go +++ b/pkg/property/item.go @@ -15,7 +15,7 @@ type Item interface { Datasets() []id.DatasetID IsDatasetLinked(id.DatasetSchemaID, id.DatasetID) bool IsEmpty() bool - Prune() + Prune() bool MigrateSchema(context.Context, *Schema, dataset.Loader) ValidateSchema(*SchemaGroup) error Fields(*Pointer) []*Field diff --git a/pkg/property/property.go b/pkg/property/property.go index 5c2098b8..db1f6308 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -270,15 +270,20 @@ func (p *Property) RemoveField(ptr *Pointer) { } } -func (p *Property) Prune() { +func (p *Property) Prune() (res bool) { if p == nil { return } - for _, f := range p.items { - if f.IsEmpty() { - p.RemoveItem(PointItem(f.ID())) + for _, i := range p.items { + if i.Prune() { + res = true + } + if i.IsEmpty() { + p.RemoveItem(PointItem(i.ID())) + res = true } } + return } func (p *Property) UpdateValue(ps *Schema, ptr *Pointer, v *Value) (*Field, *GroupList, *Group, error) { diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index ea102ca5..6d10b906 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -653,3 +653,57 @@ func TestProperty_Cast(t *testing.T) { }) } } + +func TestProperty_Prune(t *testing.T) { + tests := []struct { + name string + target *Property + wantRes bool + wantItems []Item + }{ + { + name: "ok", + target: &Property{ + items: []Item{ + &Group{}, + &GroupList{}, + }, + }, + wantRes: true, + wantItems: []Item{}, + }, + { + name: "not pruned", + target: &Property{ + items: []Item{ + &Group{fields: []*Field{testField1.Clone()}}, + }, + }, + wantRes: false, + wantItems: []Item{ + &Group{fields: []*Field{testField1.Clone()}}, + }, + }, + { + name: "empty", + target: &Property{}, + wantRes: false, + wantItems: nil, + }, + { + name: "nil", + target: nil, + wantRes: false, + wantItems: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.wantRes, tt.target.Prune()) + if tt.target != nil { + assert.Equal(t, tt.wantItems, tt.target.items) + } + }) + } +} From c1ea4d6a55733c5486883e648eae4d6310f4038e Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 14 Dec 2021 13:38:23 +0900 Subject: [PATCH 30/55] add GuessSchema method --- pkg/property/field.go | 10 +++++ pkg/property/field_test.go | 30 ++++++++++++++ pkg/property/group.go | 15 +++++++ pkg/property/group_list.go | 23 +++++++++++ pkg/property/group_list_test.go | 59 +++++++++++++++++++++++++++ pkg/property/group_test.go | 44 +++++++++++++++++++++ pkg/property/item.go | 1 + pkg/property/property.go | 18 +++++++++ pkg/property/property_test.go | 70 +++++++++++++++++++++++++++++++++ 9 files changed, 270 insertions(+) diff --git a/pkg/property/field.go b/pkg/property/field.go index 7aa07a45..8491765a 100644 --- a/pkg/property/field.go +++ b/pkg/property/field.go @@ -181,3 +181,13 @@ func (p *Field) MigrateSchema(ctx context.Context, newSchema *Schema, dl dataset return !invalid } + +func (f *Field) GuessSchema() *SchemaField { + if f == nil { + return nil + } + if f, err := NewSchemaField().ID(f.Field()).Type(f.Type()).Build(); err == nil { + return f + } + return nil +} diff --git a/pkg/property/field_test.go b/pkg/property/field_test.go index de1d4f2a..29f12930 100644 --- a/pkg/property/field_test.go +++ b/pkg/property/field_test.go @@ -288,3 +288,33 @@ func TestField_Cast(t *testing.T) { }) } } + +func TestField_GuessSchema(t *testing.T) { + tests := []struct { + name string + target *Field + want *SchemaField + }{ + { + name: "ok", + target: &Field{field: "a", v: NewOptionalValue(ValueTypeLatLng, nil)}, + want: &SchemaField{id: "a", propertyType: ValueTypeLatLng}, + }, + { + name: "empty", + target: &Field{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.GuessSchema()) + }) + } +} diff --git a/pkg/property/group.go b/pkg/property/group.go index 63d99d09..26b2e1d0 100644 --- a/pkg/property/group.go +++ b/pkg/property/group.go @@ -289,3 +289,18 @@ func (p *Group) GroupAndFields() []GroupAndField { } return res } + +func (g *Group) GuessSchema() *SchemaGroup { + if g == nil { + return nil + } + + fields := make([]*SchemaField, 0, len(g.fields)) + for _, f := range g.fields { + if sf := f.GuessSchema(); sf != nil { + fields = append(fields, sf) + } + } + + return NewSchemaGroup().ID(g.SchemaGroup()).Fields(fields).Build() +} diff --git a/pkg/property/group_list.go b/pkg/property/group_list.go index 26f44403..e4ae9344 100644 --- a/pkg/property/group_list.go +++ b/pkg/property/group_list.go @@ -415,3 +415,26 @@ func (p *GroupList) GroupAndFields() []GroupAndField { } return res } + +func (g *GroupList) GuessSchema() *SchemaGroup { + if g == nil { + return nil + } + + fieldm := map[FieldID]struct{}{} + fields := []*SchemaField{} + + for _, g := range g.groups { + if gsg := g.GuessSchema(); gsg != nil { + for _, f := range gsg.Fields() { + if _, ok := fieldm[f.ID()]; ok { + continue + } + fields = append(fields, f) + fieldm[f.ID()] = struct{}{} + } + } + } + + return NewSchemaGroup().ID(g.SchemaGroup()).IsList(true).Fields(fields).Build() +} diff --git a/pkg/property/group_list_test.go b/pkg/property/group_list_test.go index 9d978539..43c4bfbe 100644 --- a/pkg/property/group_list_test.go +++ b/pkg/property/group_list_test.go @@ -1010,3 +1010,62 @@ func TestGroupList_GroupAndFields(t *testing.T) { }) } } + +func TestGroupList_GuessSchema(t *testing.T) { + tests := []struct { + name string + target *GroupList + want *SchemaGroup + }{ + { + name: "ok", + target: &GroupList{ + itemBase: itemBase{ + SchemaGroup: "aa", + }, + groups: []*Group{ + { + itemBase: itemBase{ + SchemaGroup: "aa", + }, + fields: []*Field{ + {field: "a", v: NewOptionalValue(ValueTypeLatLng, nil)}, + }, + }, + { + itemBase: itemBase{ + SchemaGroup: "aa", + }, + fields: []*Field{ + {field: "b", v: NewOptionalValue(ValueTypeString, nil)}, + }, + }, + }, + }, + want: &SchemaGroup{ + id: "aa", + list: true, + fields: []*SchemaField{ + {id: "a", propertyType: ValueTypeLatLng}, + {id: "b", propertyType: ValueTypeString}, + }, + }, + }, + { + name: "empty", + target: &GroupList{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.GuessSchema()) + }) + } +} diff --git a/pkg/property/group_test.go b/pkg/property/group_test.go index 9c9715e9..b2757a8c 100644 --- a/pkg/property/group_test.go +++ b/pkg/property/group_test.go @@ -751,3 +751,47 @@ func TestGroup_GroupAndFields(t *testing.T) { }) } } + +func TestGroup_GuessSchema(t *testing.T) { + tests := []struct { + name string + target *Group + want *SchemaGroup + }{ + { + name: "ok", + target: &Group{ + itemBase: itemBase{ + SchemaGroup: "aa", + }, + fields: []*Field{ + {field: "a", v: NewOptionalValue(ValueTypeLatLng, nil)}, + {field: "b", v: NewOptionalValue(ValueTypeNumber, nil)}, + }, + }, + want: &SchemaGroup{ + id: "aa", + fields: []*SchemaField{ + {id: "a", propertyType: ValueTypeLatLng}, + {id: "b", propertyType: ValueTypeNumber}, + }, + }, + }, + { + name: "empty", + target: &Group{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.GuessSchema()) + }) + } +} diff --git a/pkg/property/item.go b/pkg/property/item.go index 18b5104a..a2230ea8 100644 --- a/pkg/property/item.go +++ b/pkg/property/item.go @@ -22,6 +22,7 @@ type Item interface { RemoveFields(*Pointer) bool CloneItem() Item GroupAndFields() []GroupAndField + GuessSchema() *SchemaGroup } type itemBase struct { diff --git a/pkg/property/property.go b/pkg/property/property.go index db1f6308..5ed3dd51 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -572,3 +572,21 @@ func (p *Property) Cast(ptr *Pointer, t ValueType) (res bool) { } return } + +func (p *Property) GuessSchema() *Schema { + if p == nil { + return nil + } + + groups := make([]*SchemaGroup, 0, len(p.items)) + for _, i := range p.items { + if g := i.GuessSchema(); g != nil { + groups = append(groups, g) + } + } + + if s, err := NewSchema().ID(p.Schema()).GroupList(NewSchemaGroupList(groups)).Build(); err == nil { + return s + } + return nil +} diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index 6d10b906..53b920b3 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -707,3 +707,73 @@ func TestProperty_Prune(t *testing.T) { }) } } + +func TestProperty_GuessSchema(t *testing.T) { + tests := []struct { + name string + target *Property + want *Schema + }{ + { + name: "ok", + target: &Property{ + schema: MustSchemaID("x~1.1.1/a"), + items: []Item{ + &Group{ + itemBase: itemBase{SchemaGroup: "aa"}, + fields: []*Field{ + {field: "a", v: NewOptionalValue(ValueTypeString, nil)}, + }, + }, + &GroupList{ + itemBase: itemBase{SchemaGroup: "bb"}, + groups: []*Group{ + { + itemBase: itemBase{SchemaGroup: "aa"}, + fields: []*Field{ + {field: "b", v: NewOptionalValue(ValueTypeLatLng, nil)}, + }, + }, + }, + }, + }, + }, + want: &Schema{ + id: MustSchemaID("x~1.1.1/a"), + groups: &SchemaGroupList{ + groups: []*SchemaGroup{ + { + id: "aa", + fields: []*SchemaField{ + {id: "a", propertyType: ValueTypeString}, + }, + }, + { + id: "bb", + list: true, + fields: []*SchemaField{ + {id: "b", propertyType: ValueTypeLatLng}, + }, + }, + }, + }, + }, + }, + { + name: "empty", + target: &Property{}, + want: nil, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.GuessSchema()) + }) + } +} From 6865e3bfeb973057fa90c95404018572ab63feff Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 14 Dec 2021 13:51:15 +0900 Subject: [PATCH 31/55] impl property.SchemaDiff --- pkg/property/diff.go | 55 +++++++++++ pkg/property/diff_test.go | 201 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 pkg/property/diff.go create mode 100644 pkg/property/diff_test.go diff --git a/pkg/property/diff.go b/pkg/property/diff.go new file mode 100644 index 00000000..ec7fff6a --- /dev/null +++ b/pkg/property/diff.go @@ -0,0 +1,55 @@ +package property + +type SchemaDiff struct { + Deleted []SchemaDiffDeleted + Moved []SchemaDiffMoved + TypeChanged []SchemaDiffTypeChanged +} + +type SchemaDiffDeleted SchemaFieldPointer + +type SchemaDiffMoved struct { + From SchemaFieldPointer + To SchemaFieldPointer + ToList bool +} + +type SchemaDiffTypeChanged struct { + SchemaFieldPointer + NewType ValueType +} + +func SchemaDiffFrom(old, new *Schema) (d SchemaDiff) { + if old == nil || new == nil || old == new { + return + } + + for _, gf := range old.Groups().GroupAndFields() { + ngf := new.Groups().GroupAndField(gf.Field.ID()) + if ngf == nil { + d.Deleted = append(d.Deleted, SchemaDiffDeleted(gf.SchemaFieldPointer())) + continue + } + + if ngf.Group.ID() != gf.Group.ID() { + d.Moved = append(d.Moved, SchemaDiffMoved{ + From: gf.SchemaFieldPointer(), + To: ngf.SchemaFieldPointer(), + ToList: ngf.Group.IsList(), + }) + } + + if ngf.Field.Type() != gf.Field.Type() { + d.TypeChanged = append(d.TypeChanged, SchemaDiffTypeChanged{ + SchemaFieldPointer: ngf.SchemaFieldPointer(), + NewType: ngf.Field.Type(), + }) + } + } + + return +} + +func SchemaDiffFromProperty(old *Property, new *Schema) (d SchemaDiff) { + return SchemaDiffFrom(old.GuessSchema(), new) +} diff --git a/pkg/property/diff_test.go b/pkg/property/diff_test.go new file mode 100644 index 00000000..7ab44bbd --- /dev/null +++ b/pkg/property/diff_test.go @@ -0,0 +1,201 @@ +package property + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSchemaDiffFrom(t *testing.T) { + type args struct { + old *Schema + new *Schema + } + tests := []struct { + name string + args args + want SchemaDiff + }{ + { + name: "diff", + args: args{ + old: &Schema{ + groups: &SchemaGroupList{groups: []*SchemaGroup{ + {id: "a", fields: []*SchemaField{ + {id: "aa", propertyType: ValueTypeString}, // deleted + {id: "ab", propertyType: ValueTypeString}, + {id: "ac", propertyType: ValueTypeString}, + {id: "ad", propertyType: ValueTypeString}, + }}, + }}, + }, + new: &Schema{ + groups: &SchemaGroupList{groups: []*SchemaGroup{ + {id: "a", fields: []*SchemaField{ + {id: "ab", propertyType: ValueTypeNumber}, // type changed + {id: "ae", propertyType: ValueTypeString}, // added + }}, + {id: "b", list: true, fields: []*SchemaField{ + {id: "ac", propertyType: ValueTypeString}, // moved + {id: "ad", propertyType: ValueTypeNumber}, // moved and type changed + }}, + }}, + }, + }, + want: SchemaDiff{ + Deleted: []SchemaDiffDeleted{ + {SchemaGroup: "a", Field: "aa"}, + }, + Moved: []SchemaDiffMoved{ + {From: SchemaFieldPointer{SchemaGroup: "a", Field: "ac"}, To: SchemaFieldPointer{SchemaGroup: "b", Field: "ac"}, ToList: true}, + {From: SchemaFieldPointer{SchemaGroup: "a", Field: "ad"}, To: SchemaFieldPointer{SchemaGroup: "b", Field: "ad"}, ToList: true}, + }, + TypeChanged: []SchemaDiffTypeChanged{ + {SchemaFieldPointer: SchemaFieldPointer{SchemaGroup: "a", Field: "ab"}, NewType: ValueTypeNumber}, + {SchemaFieldPointer: SchemaFieldPointer{SchemaGroup: "b", Field: "ad"}, NewType: ValueTypeNumber}, + }, + }, + }, + { + name: "no diff", + args: args{ + old: &Schema{ + groups: &SchemaGroupList{groups: []*SchemaGroup{ + {id: "a", fields: []*SchemaField{ + {id: "aa", propertyType: ValueTypeNumber}, + }}, + }}, + }, + new: &Schema{ + groups: &SchemaGroupList{groups: []*SchemaGroup{ + {id: "a", fields: []*SchemaField{ + {id: "aa", propertyType: ValueTypeNumber}, + }}, + {id: "b", list: true, fields: []*SchemaField{ + {id: "ba", propertyType: ValueTypeString}, // added + }}, + }}, + }, + }, + want: SchemaDiff{}, + }, + { + name: "same schemas", + args: args{ + old: testSchema1, + new: testSchema1, + }, + want: SchemaDiff{}, + }, + { + name: "nil", + args: args{ + old: nil, + new: nil, + }, + want: SchemaDiff{}, + }, + { + name: "old nil", + args: args{ + old: nil, + new: testSchema1, + }, + want: SchemaDiff{}, + }, + { + name: "new nil", + args: args{ + old: testSchema1, + new: nil, + }, + want: SchemaDiff{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, SchemaDiffFrom(tt.args.old, tt.args.new)) + }) + } +} + +func TestSchemaDiffFromProperty(t *testing.T) { + type args struct { + old *Property + new *Schema + } + tests := []struct { + name string + args args + want SchemaDiff + }{ + { + name: "diff", + args: args{ + old: testProperty1, + new: &Schema{ + groups: &SchemaGroupList{groups: []*SchemaGroup{ + {id: testSchemaGroup1.ID(), fields: []*SchemaField{ + {id: testSchemaField1.ID(), propertyType: ValueTypeNumber}, // type changed + {id: testSchemaField3.ID(), propertyType: ValueTypeNumber}, // moved and type changed + {id: "xxxx", propertyType: ValueTypeString}, // added + }}, + {id: testSchemaGroup2.ID(), list: true, fields: []*SchemaField{}}, + }}, + }, + }, + want: SchemaDiff{ + Deleted: nil, + Moved: []SchemaDiffMoved{ + { + From: SchemaFieldPointer{SchemaGroup: testSchemaGroup2.ID(), Field: testSchemaField3.ID()}, + To: SchemaFieldPointer{SchemaGroup: testSchemaGroup1.ID(), Field: testSchemaField3.ID()}, + }, + }, + TypeChanged: []SchemaDiffTypeChanged{ + {SchemaFieldPointer: SchemaFieldPointer{SchemaGroup: testSchemaGroup1.ID(), Field: testSchemaField1.ID()}, NewType: ValueTypeNumber}, + {SchemaFieldPointer: SchemaFieldPointer{SchemaGroup: testSchemaGroup1.ID(), Field: testSchemaField3.ID()}, NewType: ValueTypeNumber}, + }, + }, + }, + { + name: "no diff", + args: args{ + old: testProperty1, + new: testSchema1, + }, + want: SchemaDiff{}, + }, + { + name: "nil", + args: args{ + old: nil, + new: nil, + }, + want: SchemaDiff{}, + }, + { + name: "old nil", + args: args{ + old: nil, + new: testSchema1, + }, + want: SchemaDiff{}, + }, + { + name: "new nil", + args: args{ + old: testProperty1, + new: nil, + }, + want: SchemaDiff{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, SchemaDiffFromProperty(tt.args.old, tt.args.new)) + }) + } +} From 337a2bd87ea08cc72d3e3635da3d932483fa8479 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 14 Dec 2021 18:02:03 +0900 Subject: [PATCH 32/55] GroupAndFields accepts pointer --- pkg/property/group.go | 12 +++++++----- pkg/property/group_list.go | 16 +++++++++------- pkg/property/group_list_test.go | 22 ++++++++++++++++++++-- pkg/property/group_test.go | 22 ++++++++++++++++++++-- pkg/property/item.go | 2 +- pkg/property/property.go | 6 ++++-- pkg/property/property_test.go | 22 ++++++++++++++++++++-- 7 files changed, 81 insertions(+), 21 deletions(-) diff --git a/pkg/property/group.go b/pkg/property/group.go index 26b2e1d0..eb28ec2b 100644 --- a/pkg/property/group.go +++ b/pkg/property/group.go @@ -276,16 +276,18 @@ func (g *Group) RemoveFields(ptr *Pointer) (res bool) { return } -func (p *Group) GroupAndFields() []GroupAndField { +func (p *Group) GroupAndFields(ptr *Pointer) []GroupAndField { if p == nil || len(p.fields) == 0 { return nil } res := []GroupAndField{} for _, f := range p.fields { - res = append(res, GroupAndField{ - Group: p, - Field: f, - }) + if ptr == nil || ptr.Test(p.SchemaGroup(), p.ID(), f.Field()) { + res = append(res, GroupAndField{ + Group: p, + Field: f, + }) + } } return res } diff --git a/pkg/property/group_list.go b/pkg/property/group_list.go index e4ae9344..d1e7e647 100644 --- a/pkg/property/group_list.go +++ b/pkg/property/group_list.go @@ -399,18 +399,20 @@ func (g *GroupList) RemoveFields(ptr *Pointer) (res bool) { return } -func (p *GroupList) GroupAndFields() []GroupAndField { +func (p *GroupList) GroupAndFields(ptr *Pointer) []GroupAndField { if p == nil || len(p.groups) == 0 { return nil } res := []GroupAndField{} for _, g := range p.groups { - for _, r := range g.GroupAndFields() { - res = append(res, GroupAndField{ - ParentGroup: p, - Group: r.Group, - Field: r.Field, - }) + if ptr == nil || ptr.TestItem(g.SchemaGroup(), g.ID()) { + for _, r := range g.GroupAndFields(ptr) { + res = append(res, GroupAndField{ + ParentGroup: p, + Group: r.Group, + Field: r.Field, + }) + } } } return res diff --git a/pkg/property/group_list_test.go b/pkg/property/group_list_test.go index 43c4bfbe..b4c87467 100644 --- a/pkg/property/group_list_test.go +++ b/pkg/property/group_list_test.go @@ -977,30 +977,48 @@ func TestGroupList_GroupAndFields(t *testing.T) { tests := []struct { name string target *GroupList + args *Pointer want []GroupAndField }{ { - name: "ok", + name: "all", + target: testGroupList1, + args: nil, + want: []GroupAndField{ + {ParentGroup: testGroupList1, Group: testGroup2, Field: testField2}, + }, + }, + { + name: "specified", target: testGroupList1, + args: PointFieldByItem(testGroup2.ID(), testField2.Field()), want: []GroupAndField{ {ParentGroup: testGroupList1, Group: testGroup2, Field: testField2}, }, }, + { + name: "specified but not found", + target: testGroupList1, + args: PointFieldByItem(testGroup1.ID(), testField2.Field()), + want: []GroupAndField{}, + }, { name: "empty", target: &GroupList{}, + args: nil, want: nil, }, { name: "nil", target: nil, + args: nil, want: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - res := tt.target.GroupAndFields() + res := tt.target.GroupAndFields(tt.args) assert.Equal(t, tt.want, res) for i, r := range res { assert.Same(t, tt.want[i].Field, r.Field) diff --git a/pkg/property/group_test.go b/pkg/property/group_test.go index b2757a8c..ad69baa3 100644 --- a/pkg/property/group_test.go +++ b/pkg/property/group_test.go @@ -718,30 +718,48 @@ func TestGroup_GroupAndFields(t *testing.T) { tests := []struct { name string target *Group + args *Pointer want []GroupAndField }{ { - name: "ok", + name: "all", + target: testGroup1, + args: nil, + want: []GroupAndField{ + {Group: testGroup1, Field: testField1}, + }, + }, + { + name: "specified", target: testGroup1, + args: PointFieldByItem(testGroup1.ID(), testField1.Field()), want: []GroupAndField{ {Group: testGroup1, Field: testField1}, }, }, + { + name: "specified but not found", + target: testGroup1, + args: PointFieldByItem(testGroup1.ID(), testField2.Field()), + want: []GroupAndField{}, + }, { name: "empty", target: &Group{}, + args: nil, want: nil, }, { name: "nil", target: nil, + args: nil, want: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - res := tt.target.GroupAndFields() + res := tt.target.GroupAndFields(tt.args) assert.Equal(t, tt.want, res) for i, r := range res { assert.Same(t, tt.want[i].Field, r.Field) diff --git a/pkg/property/item.go b/pkg/property/item.go index a2230ea8..06ceec63 100644 --- a/pkg/property/item.go +++ b/pkg/property/item.go @@ -21,7 +21,7 @@ type Item interface { Fields(*Pointer) []*Field RemoveFields(*Pointer) bool CloneItem() Item - GroupAndFields() []GroupAndField + GroupAndFields(*Pointer) []GroupAndField GuessSchema() *SchemaGroup } diff --git a/pkg/property/property.go b/pkg/property/property.go index 5ed3dd51..290387a5 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -552,13 +552,15 @@ func (p *Property) MoveFields(f FieldID, from, to SchemaGroupID) (res bool) { return } -func (p *Property) GroupAndFields() []GroupAndField { +func (p *Property) GroupAndFields(ptr *Pointer) []GroupAndField { if p == nil || len(p.items) == 0 { return nil } res := []GroupAndField{} for _, i := range p.items { - res = append(res, i.GroupAndFields()...) + if ptr == nil || ptr.TestItem(i.SchemaGroup(), i.ID()) { + res = append(res, i.GroupAndFields(ptr)...) + } } return res } diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index 53b920b3..a5a9152e 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -548,31 +548,49 @@ func TestProperty_GroupAndFields(t *testing.T) { tests := []struct { name string target *Property + args *Pointer want []GroupAndField }{ { - name: "ok", + name: "all", target: testProperty1, + args: nil, want: []GroupAndField{ {Group: testGroup1, Field: testField1}, {ParentGroup: testGroupList1, Group: testGroup2, Field: testField2}, }, }, + { + name: "specified", + target: testProperty1, + args: PointFieldBySchemaGroup(testGroupList1.SchemaGroup(), testField2.Field()), + want: []GroupAndField{ + {ParentGroup: testGroupList1, Group: testGroup2, Field: testField2}, + }, + }, + { + name: "invalid field", + target: testProperty1, + args: PointFieldBySchemaGroup(testGroupList1.SchemaGroup(), testField1.Field()), + want: []GroupAndField{}, + }, { name: "empty", target: &Property{}, + args: nil, want: nil, }, { name: "nil", target: &Property{}, + args: nil, want: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - res := tt.target.GroupAndFields() + res := tt.target.GroupAndFields(tt.args) assert.Equal(t, tt.want, res) for i, r := range res { assert.Same(t, tt.want[i].Field, r.Field) From 4ca9d0d9939fae9b4c6d87bff112b58ca417e9e1 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 14 Dec 2021 18:06:07 +0900 Subject: [PATCH 33/55] fix property.Field.Cast --- pkg/property/field.go | 2 +- pkg/property/field_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/property/field.go b/pkg/property/field.go index 8491765a..cadd6e2f 100644 --- a/pkg/property/field.go +++ b/pkg/property/field.go @@ -113,7 +113,7 @@ func (p *Field) Update(value *Value, field *SchemaField) error { } func (p *Field) Cast(t ValueType) bool { - if p.IsEmpty() || p.Type() == t { + if p == nil || p.Type() == ValueTypeUnknown || p.Type() == t { return false } p.v = p.v.Cast(t) diff --git a/pkg/property/field_test.go b/pkg/property/field_test.go index 29f12930..165c9ff9 100644 --- a/pkg/property/field_test.go +++ b/pkg/property/field_test.go @@ -157,7 +157,7 @@ func TestField_IsEmpty(t *testing.T) { { name: "nil", target: nil, - want: false, + want: true, }, } From 9290f69f5e0c8241beed41da929ddfd0e80cb194 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 14 Dec 2021 18:45:41 +0900 Subject: [PATCH 34/55] update property.MoveFields, add tests --- pkg/property/property.go | 93 +++++++------ pkg/property/property_test.go | 240 +++++++++++++++++++++++++++++----- 2 files changed, 253 insertions(+), 80 deletions(-) diff --git a/pkg/property/property.go b/pkg/property/property.go index 290387a5..b29250fe 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -42,15 +42,9 @@ func (p *Property) Field(ptr *Pointer) (*Field, *GroupList, *Group) { return nil, nil, nil } - if iid, fid, ok := ptr.FieldByItem(); ok { - if i, gl := p.Item(iid); i != nil { - g := ToGroup(i) - return g.Field(fid), gl, g - } - } else if sgid, fid, ok := ptr.FieldBySchemaGroup(); ok { - if i := p.ItemBySchema(sgid); i != nil { - g := ToGroup(i) - return g.Field(fid), nil, g + if g, gl := p.GroupAndList(ptr); g != nil { + if fields := g.Fields(ptr); len(fields) > 0 { + return fields[0], gl, g } } @@ -64,20 +58,35 @@ func (p *Property) Items() []Item { return append([]Item{}, p.items...) } -func (p *Property) Item(id ItemID) (Item, *GroupList) { - if p == nil { - return nil, nil +func (p *Property) Item(ptr *Pointer) Item { + if p == nil || ptr == nil || ptr.FieldOnlyRef() != nil { + return nil } - for _, f := range p.items { - if f.ID() == id { - return f, nil + + for _, i := range p.items { + if ptr.TestItem(i.SchemaGroup(), i.ID()) { + return i } - if gl := ToGroupList(f); gl != nil { - if i := gl.Group(id); i != nil { - return i, gl + } + + return nil +} + +func (p *Property) GroupAndList(ptr *Pointer) (*Group, *GroupList) { + if p == nil || ptr == nil { + return nil, nil + } + + for _, i := range p.items { + if ptr.TestItem(i.SchemaGroup(), i.ID()) { + if gl := ToGroupList(i); gl != nil { + return gl.GroupByPointer(ptr), gl + } else if g := ToGroup(i); g != nil { + return g, nil } } } + return nil, nil } @@ -116,18 +125,6 @@ func (p *Property) GroupListBySchema(id SchemaGroupID) *GroupList { return nil } -func (p *Property) ItemByPointer(ptr *Pointer) (Item, *GroupList) { - if p == nil || ptr == nil { - return nil, nil - } - if pid, ok := ptr.Item(); ok { - return p.Item(pid) - } else if sgid, ok := ptr.ItemBySchemaGroup(); ok { - return p.ItemBySchema(sgid), nil - } - return nil, nil -} - func (p *Property) ListItem(ptr *Pointer) (*Group, *GroupList) { if p == nil { return nil, nil @@ -264,8 +261,7 @@ func (p *Property) RemoveField(ptr *Pointer) { return } - item, _ := p.ItemByPointer(ptr) - if group := ToGroup(item); group != nil { + if group := ToGroup(p.Item(ptr)); group != nil { group.RemoveField(fid) } } @@ -339,8 +335,11 @@ func (p *Property) GetOrCreateItem(ps *Schema, ptr *Pointer) (Item, *GroupList) return nil, nil } - if item, pgl := p.ItemByPointer(ptr); item != nil { - return item, pgl + if g, gl := p.GroupAndList(ptr); g != nil || gl != nil { + if g == nil { + return gl, nil + } + return g, gl } psgid, ok := ptr.ItemBySchemaGroup() @@ -355,11 +354,7 @@ func (p *Property) GetOrCreateItem(ps *Schema, ptr *Pointer) (Item, *GroupList) ni := InitItemFrom(psg) if ni != nil { - if p.items == nil { - p.items = []Item{ni} - } else { - p.items = append(p.items, ni) - } + p.items = append(p.items, ni) } return ni, nil // root item @@ -523,28 +518,28 @@ func (p *Property) ValidateSchema(ps *Schema) error { } // MoveFields moves fields between items. Only fields in Groups can be moved to another Group, fields in GroupLists will simply be deleted. -func (p *Property) MoveFields(f FieldID, from, to SchemaGroupID) (res bool) { +func (p *Property) MoveFields(from, to *Pointer) (res bool) { if p == nil { return } - fromItem := p.ItemBySchema(from) - if fromItem == nil { + fields := p.GroupAndFields(from) + if len(fields) == 0 { return } - fields := p.Fields(PointFieldBySchemaGroup(from, f)) - if len(fields) == 0 { - return + toGroup := ToGroup(p.Item(to)) + if toGroup != nil { + // create toGroup } - toGroup := p.GroupBySchema(to) for _, f := range fields { - if fromItem.RemoveFields(PointFieldOnly(f.Field())) { + if f.Group.RemoveField(f.Field.Field()) { res = true } - if toGroup != nil { - toGroup.AddFields(f) + if f.ParentGroup == nil && toGroup != nil { + // NOTE: currently changing the field ID is not supported + toGroup.AddFields(f.Field) res = true } } diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index a5a9152e..8dadd1e5 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -14,7 +14,7 @@ var ( testProperty1 = New().NewID().Schema(testSchema1.ID()).Scene(id.NewSceneID()).Items([]Item{testGroup1, testGroupList1}).MustBuild() ) -func TestPropertyMigrateSchema(t *testing.T) { +func TestProperty_MigrateSchema(t *testing.T) { sceneID := id.NewSceneID() oldSchema := id.MustPropertySchemaID("hoge~1.0.0/test") newSchema := id.MustPropertySchemaID("hoge~1.0.0/test2") @@ -119,7 +119,7 @@ func TestPropertyMigrateSchema(t *testing.T) { assert.NotNil(t, newGroup.Field(schemaField5ID)) } -func TestGetOrCreateItem(t *testing.T) { +func TestProperty_GetOrCreateItem(t *testing.T) { sceneID := id.NewSceneID() sid := id.MustPropertySchemaID("hoge~1.0.0/test") sf1id := id.PropertySchemaFieldID("a") @@ -139,13 +139,15 @@ func TestGetOrCreateItem(t *testing.T) { assert.Nil(t, p.ItemBySchema(sg1id)) assert.Equal(t, []Item{}, p.Items()) - i, _ := p.GetOrCreateItem(s, PointItemBySchema(sg1id)) + i, gl := p.GetOrCreateItem(s, PointItemBySchema(sg1id)) + assert.Nil(t, gl) assert.NotNil(t, i) assert.Equal(t, sg1id, i.SchemaGroup()) assert.Equal(t, i, ToGroup(p.ItemBySchema(sg1id))) assert.Equal(t, []Item{i}, p.Items()) - i2, _ := p.GetOrCreateItem(s, PointItemBySchema(sg1id)) + i2, gl := p.GetOrCreateItem(s, PointItemBySchema(sg1id)) + assert.Nil(t, gl) assert.NotNil(t, i2) assert.Equal(t, i, i2) assert.Equal(t, i2, ToGroup(p.ItemBySchema(sg1id))) @@ -154,20 +156,20 @@ func TestGetOrCreateItem(t *testing.T) { // group list assert.Nil(t, p.ItemBySchema(sg2id)) - i3, _ := p.GetOrCreateItem(s, PointItemBySchema(sg2id)) - assert.NotNil(t, i3) + i3, gl := p.GetOrCreateItem(s, PointItemBySchema(sg2id)) + assert.Nil(t, gl) assert.Equal(t, sg2id, i3.SchemaGroup()) assert.Equal(t, i3, ToGroupList(p.ItemBySchema(sg2id))) assert.Equal(t, []Item{i, i3}, p.Items()) - i4, _ := p.GetOrCreateItem(s, PointItemBySchema(sg2id)) - assert.NotNil(t, i4) + i4, gl := p.GetOrCreateItem(s, PointItemBySchema(sg2id)) + assert.Nil(t, gl) assert.Equal(t, i3, i4) assert.Equal(t, i4, ToGroupList(p.ItemBySchema(sg2id))) assert.Equal(t, []Item{i2, i4}, p.Items()) } -func TestGetOrCreateField(t *testing.T) { +func TestProperty_GetOrCreateField(t *testing.T) { sceneID := id.NewSceneID() sid := id.MustPropertySchemaID("hoge~1.0.0/test") sf1id := id.PropertySchemaFieldID("a") @@ -423,6 +425,7 @@ func TestProperty_MoveFields(t *testing.T) { sg2 := SchemaGroupID("bbb") sg3 := SchemaGroupID("ccc") sg4 := SchemaGroupID("ddd") + sg5 := SchemaGroupID("eee") f1 := NewField().Field(FieldID("x")).Value(OptionalValueFrom(ValueTypeString.ValueFrom("aaa"))).Build() f2 := NewField().Field(FieldID("y")).Value(OptionalValueFrom(ValueTypeString.ValueFrom("bbb"))).Build() @@ -447,13 +450,14 @@ func TestProperty_MoveFields(t *testing.T) { type args struct { f FieldID - from SchemaGroupID - to SchemaGroupID + from *Pointer + to *Pointer } tests := []struct { name string target *Property args args + want bool fromFields []*Field toFields []*Field }{ @@ -462,20 +466,35 @@ func TestProperty_MoveFields(t *testing.T) { target: p.Clone(), args: args{ f: f1.Field(), - from: sg1, - to: sg2, + from: PointFieldBySchemaGroup(sg1, f1.Field()), + to: PointFieldBySchemaGroup(sg2, f1.Field()), }, + want: true, fromFields: []*Field{}, // deleted toFields: []*Field{f1}, // added }, + { + name: "group->new group", + target: p.Clone(), + args: args{ + f: f1.Field(), + from: PointFieldBySchemaGroup(sg1, f1.Field()), + to: PointFieldBySchemaGroup(sg5, f1.Field()), + }, + want: true, + fromFields: []*Field{}, // deleted + toFields: []*Field{}, // not added + // toFields: []*Field{f1}, // added + }, { name: "group->group failed", target: p.Clone(), args: args{ f: f2.Field(), - from: sg1, - to: sg2, + from: PointFieldBySchemaGroup(sg1, f2.Field()), + to: PointFieldBySchemaGroup(sg2, f2.Field()), }, + want: false, fromFields: []*Field{f1}, // not deleted toFields: []*Field{}, // not added }, @@ -484,31 +503,34 @@ func TestProperty_MoveFields(t *testing.T) { target: p.Clone(), args: args{ f: f2.Field(), - from: sg3, - to: sg4, + from: PointFieldBySchemaGroup(sg3, f2.Field()), + to: PointFieldBySchemaGroup(sg4, f2.Field()), }, + want: true, fromFields: []*Field{}, // deleted toFields: []*Field{}, // not added }, { name: "group->group list", - target: testProperty1.Clone(), + target: p.Clone(), args: args{ f: f1.Field(), - from: sg1, - to: sg4, + from: PointFieldBySchemaGroup(sg1, f1.Field()), + to: PointFieldBySchemaGroup(sg4, f1.Field()), }, + want: true, fromFields: []*Field{}, // deleted toFields: []*Field{}, // not added }, { name: "group list->group", - target: testProperty1.Clone(), + target: p.Clone(), args: args{ f: f2.Field(), - from: sg3, - to: sg2, + from: PointFieldBySchemaGroup(sg3, f2.Field()), + to: PointFieldBySchemaGroup(sg2, f2.Field()), }, + want: true, fromFields: []*Field{}, // deleted toFields: []*Field{}, // not added }, @@ -517,19 +539,20 @@ func TestProperty_MoveFields(t *testing.T) { target: &Property{}, args: args{ f: f1.Field(), - from: sg1, - to: sg2, + from: PointFieldBySchemaGroup(sg1, f1.Field()), + to: PointFieldBySchemaGroup(sg2, f1.Field()), }, + want: false, fromFields: nil, toFields: nil, }, { name: "nil", args: args{ - f: f1.Field(), - from: sg1, - to: sg2, + from: PointFieldBySchemaGroup(sg1, f1.Field()), + to: PointFieldBySchemaGroup(sg2, f1.Field()), }, + want: false, fromFields: nil, toFields: nil, }, @@ -537,9 +560,9 @@ func TestProperty_MoveFields(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - tt.target.MoveFields(tt.args.f, tt.args.from, tt.args.to) - assert.Equal(t, tt.fromFields, tt.target.Fields(PointItemBySchema(tt.args.from))) - assert.Equal(t, tt.toFields, tt.target.Fields(PointItemBySchema(tt.args.to))) + assert.Equal(t, tt.want, tt.target.MoveFields(tt.args.from, tt.args.to)) + assert.Equal(t, tt.fromFields, tt.target.Fields(PointItemBySchema(*tt.args.from.schemaGroup)), "from item") + assert.Equal(t, tt.toFields, tt.target.Fields(PointItemBySchema(*tt.args.to.schemaGroup)), "to item") }) } } @@ -795,3 +818,158 @@ func TestProperty_GuessSchema(t *testing.T) { }) } } + +func TestProperty_Field(t *testing.T) { + tests := []struct { + name string + target *Property + args *Pointer + want *Field + want1 *GroupList + want2 *Group + }{ + { + name: "field by schema group", + target: testProperty1, + args: PointFieldBySchemaGroup(testGroup1.SchemaGroup(), testField1.Field()), + want: testField1, + want1: nil, + want2: testGroup1, + }, + { + name: "field by item", + target: testProperty1, + args: PointFieldByItem(testGroup1.ID(), testField1.Field()), + want: testField1, + want1: nil, + want2: testGroup1, + }, + { + name: "field only", + target: testProperty1, + args: PointFieldOnly(testField1.Field()), + want: testField1, + want1: nil, + want2: testGroup1, + }, + { + name: "field in list", + target: testProperty1, + args: PointFieldOnly(testField2.Field()), + want: nil, + want1: nil, + want2: nil, + }, + { + name: "not found", + target: testProperty1, + args: PointFieldOnly("_"), + want: nil, + want1: nil, + want2: nil, + }, + { + name: "empty", + target: &Property{}, + args: PointFieldOnly("_"), + want: nil, + want1: nil, + want2: nil, + }, + { + name: "nil pointer", + target: testProperty1, + args: nil, + want: nil, + want1: nil, + want2: nil, + }, + { + name: "nil", + target: nil, + args: PointFieldOnly("_"), + want: nil, + want1: nil, + want2: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, got1, got2 := tt.target.Field(tt.args) + assert.Equal(t, tt.want, got) + assert.Equal(t, tt.want1, got1) + assert.Equal(t, tt.want2, got2) + }) + } +} + +func TestProperty_Item(t *testing.T) { + tests := []struct { + name string + target *Property + args *Pointer + want Item + }{ + { + name: "group", + target: testProperty1, + args: PointItem(testGroup1.ID()), + want: testGroup1, + }, + { + name: "group list", + target: testProperty1, + args: PointItem(testGroupList1.ID()), + want: testGroupList1, + }, + { + name: "group by schema group", + target: testProperty1, + args: PointItemBySchema(testGroup1.SchemaGroup()), + want: testGroup1, + }, + { + name: "group list by schema group", + target: testProperty1, + args: PointItemBySchema(testGroupList1.SchemaGroup()), + want: testGroupList1, + }, + { + name: "not found", + target: testProperty1, + args: PointItemBySchema("_"), + want: nil, + }, + { + name: "field only", + target: testProperty1, + args: PointFieldOnly(testField1.Field()), + want: nil, + }, + { + name: "nil pointer", + target: testProperty1, + args: nil, + want: nil, + }, + { + name: "empty", + target: &Property{}, + args: PointFieldOnly(testField1.Field()), + want: nil, + }, + { + name: "nil", + target: nil, + args: PointFieldOnly(testField1.Field()), + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Item(tt.args)) + }) + } +} From c4c1dd38480a5305f23852b4913b1a9957ee75c6 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 14 Dec 2021 19:14:32 +0900 Subject: [PATCH 35/55] impl SchemaDiff.Migrate (wip) --- pkg/property/diff.go | 30 +++++ pkg/property/diff_test.go | 227 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 257 insertions(+) diff --git a/pkg/property/diff.go b/pkg/property/diff.go index ec7fff6a..4db28fc1 100644 --- a/pkg/property/diff.go +++ b/pkg/property/diff.go @@ -53,3 +53,33 @@ func SchemaDiffFrom(old, new *Schema) (d SchemaDiff) { func SchemaDiffFromProperty(old *Property, new *Schema) (d SchemaDiff) { return SchemaDiffFrom(old.GuessSchema(), new) } + +func (d SchemaDiff) Migrate(p *Property) (res bool) { + for _, dd := range d.Deleted { + if p.RemoveFields(SchemaFieldPointer(dd).Pointer()) { + res = true + } + } + + for _, dm := range d.Moved { + if dm.ToList { + // group -> list and list -> list are not supported; just delete + if p.RemoveFields(dm.From.Pointer()) { + res = true + } + continue + } + + if p.MoveFields(dm.From.Pointer(), dm.To.Pointer()) { + res = true + } + } + + for _, dt := range d.TypeChanged { + if p.Cast(dt.Pointer(), dt.NewType) { + res = true + } + } + + return +} diff --git a/pkg/property/diff_test.go b/pkg/property/diff_test.go index 7ab44bbd..402cdedc 100644 --- a/pkg/property/diff_test.go +++ b/pkg/property/diff_test.go @@ -199,3 +199,230 @@ func TestSchemaDiffFromProperty(t *testing.T) { }) } } + +func TestSchemaDiff_Migrate(t *testing.T) { + tests := []struct { + name string + target SchemaDiff + args *Property + want bool + wantProperty *Property + }{ + { + name: "deleted and type changed", + target: SchemaDiff{ + Deleted: []SchemaDiffDeleted{ + {SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, + }, + TypeChanged: []SchemaDiffTypeChanged{ + {SchemaFieldPointer: SchemaFieldPointer{SchemaGroup: testGroupList1.SchemaGroup(), Field: testField2.Field()}, NewType: ValueTypeString}, + }, + }, + args: testProperty1.Clone(), + want: true, + wantProperty: &Property{ + id: testProperty1.ID(), + scene: testProperty1.Scene(), + schema: testProperty1.Schema(), + items: []Item{ + &Group{ + itemBase: itemBase{ + ID: testGroup1.ID(), + SchemaGroup: testGroup1.SchemaGroup(), + }, + fields: []*Field{ + // deleted + }, + }, + &GroupList{ + itemBase: itemBase{ + ID: testGroupList1.ID(), + SchemaGroup: testGroupList1.SchemaGroup(), + }, + groups: []*Group{ + { + itemBase: itemBase{ + ID: testGroup2.ID(), + SchemaGroup: testGroup2.SchemaGroup(), + }, + fields: []*Field{ + {field: testField2.Field(), v: NewOptionalValue(ValueTypeString, nil)}, // type changed + }, + }, + }, + }, + }, + }, + }, + // { + // name: "moved", + // target: SchemaDiff{ + // Moved: []SchemaDiffMoved{ + // { + // From: SchemaFieldPointer{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, + // To: SchemaFieldPointer{SchemaGroup: "x", Field: testField1.Field()}, + // }, + // }, + // }, + // args: testProperty1.Clone(), + // want: true, + // wantProperty: &Property{ + // id: testProperty1.ID(), + // scene: testProperty1.Scene(), + // schema: testProperty1.Schema(), + // items: []Item{ + // &Group{ + // itemBase: itemBase{ + // ID: testGroup1.ID(), + // SchemaGroup: testGroup1.SchemaGroup(), + // }, + // fields: []*Field{ + // // deleted + // }, + // }, + // &Group{ + // itemBase: itemBase{ + // ID: "", // TODO + // SchemaGroup: "x", + // }, + // fields: []*Field{testField1}, + // }, + // testGroup2, + // }, + // }, + // }, + // { + // name: "moved and type changed", + // target: SchemaDiff{ + // Moved: []SchemaDiffMoved{ + // { + // From: SchemaFieldPointer{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, + // To: SchemaFieldPointer{SchemaGroup: "x", Field: testField1.Field()}, + // }, + // }, + // TypeChanged: []SchemaDiffTypeChanged{ + // {SchemaFieldPointer: SchemaFieldPointer{SchemaGroup: "x", Field: testField1.Field()}, NewType: ValueTypeNumber}, + // }, + // }, + // args: testProperty1.Clone(), + // want: true, + // wantProperty: &Property{ + // id: testProperty1.ID(), + // scene: testProperty1.Scene(), + // schema: testProperty1.Schema(), + // items: []Item{ + // &Group{ + // itemBase: itemBase{ + // ID: testGroup1.ID(), + // SchemaGroup: testGroup1.SchemaGroup(), + // }, + // fields: []*Field{ + // // deleted + // }, + // }, + // &Group{ + // itemBase: itemBase{ + // ID: "", // TODO + // SchemaGroup: "x", + // }, + // fields: []*Field{ + // {field: testField1.Field(), v: NewOptionalValue(ValueTypeNumber, nil)}, + // }, + // }, + // testGroup2, + // }, + // }, + // }, + { + name: "group -> list", + target: SchemaDiff{ + Moved: []SchemaDiffMoved{ + { + From: SchemaFieldPointer{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, + To: SchemaFieldPointer{SchemaGroup: testGroup2.SchemaGroup(), Field: testField1.Field()}, + }, + }, + }, + args: testProperty1.Clone(), + want: true, + wantProperty: &Property{ + id: testProperty1.ID(), + scene: testProperty1.Scene(), + schema: testProperty1.Schema(), + items: []Item{ + &Group{ + itemBase: itemBase{ + ID: testGroup1.ID(), + SchemaGroup: testGroup1.SchemaGroup(), + }, + fields: []*Field{ + // deleted + }, + }, + testGroupList1, + }, + }, + }, + { + name: "list -> group", + target: SchemaDiff{ + Moved: []SchemaDiffMoved{ + { + From: SchemaFieldPointer{SchemaGroup: testGroup2.SchemaGroup(), Field: testField2.Field()}, + To: SchemaFieldPointer{SchemaGroup: testGroup1.SchemaGroup(), Field: testField2.Field()}, + }, + }, + }, + args: testProperty1.Clone(), + want: true, + wantProperty: &Property{ + id: testProperty1.ID(), + scene: testProperty1.Scene(), + schema: testProperty1.Schema(), + items: []Item{ + testGroup1, + &GroupList{ + itemBase: itemBase{ + ID: testGroupList1.ID(), + SchemaGroup: testGroupList1.SchemaGroup(), + }, + groups: []*Group{ + { + itemBase: itemBase{ + ID: testGroup2.ID(), + SchemaGroup: testGroup2.SchemaGroup(), + }, + fields: []*Field{ + // deleted + }, + }, + }, + }, + }, + }, + }, + { + name: "empty", + target: SchemaDiff{}, + args: testProperty1, + want: false, + wantProperty: testProperty1, + }, + { + name: "nil property", + target: SchemaDiff{ + Deleted: []SchemaDiffDeleted{{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}}, + }, + args: nil, + want: false, + wantProperty: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Migrate(tt.args)) + assert.Equal(t, tt.wantProperty, tt.args) + }) + } +} From 89743d1fe80e609ec0200834aca2f8a30b1b0374 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 15 Dec 2021 13:57:59 +0900 Subject: [PATCH 36/55] add GetOrCreateRootGroup to property --- pkg/property/group_builder.go | 2 +- pkg/property/property.go | 23 ++++++++ pkg/property/property_test.go | 100 ++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 1 deletion(-) diff --git a/pkg/property/group_builder.go b/pkg/property/group_builder.go index e4622bcf..2bc8bdf2 100644 --- a/pkg/property/group_builder.go +++ b/pkg/property/group_builder.go @@ -46,7 +46,7 @@ func (b *GroupBuilder) ID(id id.PropertyItemID) *GroupBuilder { } func (b *GroupBuilder) NewID() *GroupBuilder { - b.p.itemBase.ID = id.NewPropertyItemID() + b.p.itemBase.ID = NewItemID() return b } diff --git a/pkg/property/property.go b/pkg/property/property.go index b29250fe..aeb9da2f 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -379,6 +379,29 @@ func (p *Property) GetOrCreateGroup(ps *Schema, ptr *Pointer) (*Group, *GroupLis return ToGroup(item), gl } +func (p *Property) GetOrCreateRootGroup(ptr *Pointer) (*Group, bool) { + if p == nil || ptr == nil { + return nil, false + } + + if g := ToGroup(p.Item(ptr)); g != nil { + return g, false + } + + sg, ok := ptr.ItemBySchemaGroup() + if !ok || p.GroupListBySchema(sg) != nil { + return nil, false + } + + ng, err := NewGroup().NewID().Schema(sg).Build() + if err != nil { + return nil, false + } + + p.items = append(p.items, ng) + return ng, true +} + func (p *Property) GetOrCreateGroupList(ps *Schema, ptr *Pointer) *GroupList { if p == nil || ps == nil || ptr == nil || !ps.ID().Equal(p.Schema()) { return nil diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index 8dadd1e5..2e9b4b68 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -973,3 +973,103 @@ func TestProperty_Item(t *testing.T) { }) } } + +func TestProperty_GetOrCreateRootGroup(t *testing.T) { + itemID := NewItemID() + NewItemID = func() ItemID { + return itemID + } + + tests := []struct { + name string + target *Property + args *Pointer + want1 *Group + want2 bool + }{ + { + name: "get", + target: &Property{ + items: []Item{ + &Group{itemBase: itemBase{SchemaGroup: "x"}}, + }, + }, + args: PointItemBySchema("x"), + want1: &Group{itemBase: itemBase{SchemaGroup: "x"}}, + want2: false, + }, + { + name: "create", + target: &Property{ + items: []Item{ + &Group{itemBase: itemBase{ID: itemID, SchemaGroup: "x"}}, + }, + }, + args: PointItemBySchema("y"), + want1: &Group{itemBase: itemBase{ID: itemID, SchemaGroup: "y"}}, + want2: true, + }, + { + name: "item pointer", + target: &Property{ + items: []Item{ + &Group{itemBase: itemBase{ID: itemID, SchemaGroup: "x"}}, + }, + }, + args: PointItem(itemID), + want1: &Group{itemBase: itemBase{ID: itemID, SchemaGroup: "x"}}, + want2: false, + }, + { + name: "item pointer but not found", + target: &Property{ + items: []Item{ + &Group{itemBase: itemBase{SchemaGroup: "x"}}, + }, + }, + args: PointItem(itemID), + want1: nil, + want2: false, + }, + { + name: "invalid pointer", + target: &Property{ + items: []Item{ + &Group{itemBase: itemBase{SchemaGroup: "x"}}, + }, + }, + args: PointFieldOnly("x"), + want1: nil, + want2: false, + }, + { + name: "list already exists", + target: &Property{ + items: []Item{ + &GroupList{itemBase: itemBase{SchemaGroup: "x"}}, + }, + }, + args: PointItemBySchema("x"), + want1: nil, + want2: false, + }, + { + name: "nil", + target: nil, + args: PointItemBySchema("x"), + want1: nil, + want2: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res1, res2 := tt.target.GetOrCreateRootGroup(tt.args) + assert.Equal(t, tt.want1, res1) + assert.Equal(t, tt.want2, res2) + if tt.target != nil && tt.want1 != nil { + assert.Contains(t, tt.target.items, tt.want1) + } + }) + } +} From 126f0ee0dac8d8a2dd46ab11cddadb98c2905314 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 15 Dec 2021 15:08:23 +0900 Subject: [PATCH 37/55] update property.MoveFields --- pkg/property/diff_test.go | 161 +++++++++++++++++----------------- pkg/property/property.go | 5 +- pkg/property/property_test.go | 5 +- 3 files changed, 85 insertions(+), 86 deletions(-) diff --git a/pkg/property/diff_test.go b/pkg/property/diff_test.go index 402cdedc..076897f0 100644 --- a/pkg/property/diff_test.go +++ b/pkg/property/diff_test.go @@ -201,6 +201,9 @@ func TestSchemaDiffFromProperty(t *testing.T) { } func TestSchemaDiff_Migrate(t *testing.T) { + itemID := NewItemID() + NewItemID = func() ItemID { return itemID } + tests := []struct { name string target SchemaDiff @@ -254,85 +257,85 @@ func TestSchemaDiff_Migrate(t *testing.T) { }, }, }, - // { - // name: "moved", - // target: SchemaDiff{ - // Moved: []SchemaDiffMoved{ - // { - // From: SchemaFieldPointer{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, - // To: SchemaFieldPointer{SchemaGroup: "x", Field: testField1.Field()}, - // }, - // }, - // }, - // args: testProperty1.Clone(), - // want: true, - // wantProperty: &Property{ - // id: testProperty1.ID(), - // scene: testProperty1.Scene(), - // schema: testProperty1.Schema(), - // items: []Item{ - // &Group{ - // itemBase: itemBase{ - // ID: testGroup1.ID(), - // SchemaGroup: testGroup1.SchemaGroup(), - // }, - // fields: []*Field{ - // // deleted - // }, - // }, - // &Group{ - // itemBase: itemBase{ - // ID: "", // TODO - // SchemaGroup: "x", - // }, - // fields: []*Field{testField1}, - // }, - // testGroup2, - // }, - // }, - // }, - // { - // name: "moved and type changed", - // target: SchemaDiff{ - // Moved: []SchemaDiffMoved{ - // { - // From: SchemaFieldPointer{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, - // To: SchemaFieldPointer{SchemaGroup: "x", Field: testField1.Field()}, - // }, - // }, - // TypeChanged: []SchemaDiffTypeChanged{ - // {SchemaFieldPointer: SchemaFieldPointer{SchemaGroup: "x", Field: testField1.Field()}, NewType: ValueTypeNumber}, - // }, - // }, - // args: testProperty1.Clone(), - // want: true, - // wantProperty: &Property{ - // id: testProperty1.ID(), - // scene: testProperty1.Scene(), - // schema: testProperty1.Schema(), - // items: []Item{ - // &Group{ - // itemBase: itemBase{ - // ID: testGroup1.ID(), - // SchemaGroup: testGroup1.SchemaGroup(), - // }, - // fields: []*Field{ - // // deleted - // }, - // }, - // &Group{ - // itemBase: itemBase{ - // ID: "", // TODO - // SchemaGroup: "x", - // }, - // fields: []*Field{ - // {field: testField1.Field(), v: NewOptionalValue(ValueTypeNumber, nil)}, - // }, - // }, - // testGroup2, - // }, - // }, - // }, + { + name: "moved", + target: SchemaDiff{ + Moved: []SchemaDiffMoved{ + { + From: SchemaFieldPointer{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, + To: SchemaFieldPointer{SchemaGroup: "x", Field: testField1.Field()}, + }, + }, + }, + args: testProperty1.Clone(), + want: true, + wantProperty: &Property{ + id: testProperty1.ID(), + scene: testProperty1.Scene(), + schema: testProperty1.Schema(), + items: []Item{ + &Group{ + itemBase: itemBase{ + ID: testGroup1.ID(), + SchemaGroup: testGroup1.SchemaGroup(), + }, + fields: []*Field{ + // deleted + }, + }, + testGroupList1, + &Group{ + itemBase: itemBase{ + ID: itemID, + SchemaGroup: "x", + }, + fields: []*Field{testField1}, + }, + }, + }, + }, + { + name: "moved and type changed", + target: SchemaDiff{ + Moved: []SchemaDiffMoved{ + { + From: SchemaFieldPointer{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, + To: SchemaFieldPointer{SchemaGroup: "x", Field: testField1.Field()}, + }, + }, + TypeChanged: []SchemaDiffTypeChanged{ + {SchemaFieldPointer: SchemaFieldPointer{SchemaGroup: "x", Field: testField1.Field()}, NewType: ValueTypeNumber}, + }, + }, + args: testProperty1.Clone(), + want: true, + wantProperty: &Property{ + id: testProperty1.ID(), + scene: testProperty1.Scene(), + schema: testProperty1.Schema(), + items: []Item{ + &Group{ + itemBase: itemBase{ + ID: testGroup1.ID(), + SchemaGroup: testGroup1.SchemaGroup(), + }, + fields: []*Field{ + // deleted + }, + }, + testGroupList1, + &Group{ + itemBase: itemBase{ + ID: itemID, + SchemaGroup: "x", + }, + fields: []*Field{ + {field: testField1.Field(), v: NewOptionalValue(ValueTypeNumber, nil)}, + }, + }, + }, + }, + }, { name: "group -> list", target: SchemaDiff{ diff --git a/pkg/property/property.go b/pkg/property/property.go index aeb9da2f..9ad5825d 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -551,10 +551,7 @@ func (p *Property) MoveFields(from, to *Pointer) (res bool) { return } - toGroup := ToGroup(p.Item(to)) - if toGroup != nil { - // create toGroup - } + toGroup, res := p.GetOrCreateRootGroup(to) for _, f := range fields { if f.Group.RemoveField(f.Field.Field()) { diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index 2e9b4b68..21d7cbd7 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -482,9 +482,8 @@ func TestProperty_MoveFields(t *testing.T) { to: PointFieldBySchemaGroup(sg5, f1.Field()), }, want: true, - fromFields: []*Field{}, // deleted - toFields: []*Field{}, // not added - // toFields: []*Field{f1}, // added + fromFields: []*Field{}, // deleted + toFields: []*Field{f1}, // added }, { name: "group->group failed", From 396883d6a4f8c786f01074078087b9c0ac51d700 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 15 Dec 2021 16:07:00 +0900 Subject: [PATCH 38/55] add id fields, IsEmpty to property.Diff --- pkg/property/diff.go | 15 +++++- pkg/property/diff_test.go | 100 ++++++++++++++++++++++++++++++++------ 2 files changed, 99 insertions(+), 16 deletions(-) diff --git a/pkg/property/diff.go b/pkg/property/diff.go index 4db28fc1..36a2bf15 100644 --- a/pkg/property/diff.go +++ b/pkg/property/diff.go @@ -1,6 +1,8 @@ package property type SchemaDiff struct { + From SchemaID + To SchemaID Deleted []SchemaDiffDeleted Moved []SchemaDiffMoved TypeChanged []SchemaDiffTypeChanged @@ -20,6 +22,9 @@ type SchemaDiffTypeChanged struct { } func SchemaDiffFrom(old, new *Schema) (d SchemaDiff) { + d.From = old.ID() + d.To = new.ID() + if old == nil || new == nil || old == new { return } @@ -54,7 +59,11 @@ func SchemaDiffFromProperty(old *Property, new *Schema) (d SchemaDiff) { return SchemaDiffFrom(old.GuessSchema(), new) } -func (d SchemaDiff) Migrate(p *Property) (res bool) { +func (d *SchemaDiff) Migrate(p *Property) (res bool) { + if d.IsEmpty() { + return + } + for _, dd := range d.Deleted { if p.RemoveFields(SchemaFieldPointer(dd).Pointer()) { res = true @@ -83,3 +92,7 @@ func (d SchemaDiff) Migrate(p *Property) (res bool) { return } + +func (d *SchemaDiff) IsEmpty() bool { + return d == nil || len(d.Deleted) == 0 && len(d.Moved) == 0 && len(d.TypeChanged) == 0 +} diff --git a/pkg/property/diff_test.go b/pkg/property/diff_test.go index 076897f0..50f94723 100644 --- a/pkg/property/diff_test.go +++ b/pkg/property/diff_test.go @@ -7,6 +7,9 @@ import ( ) func TestSchemaDiffFrom(t *testing.T) { + ps1 := MustSchemaID("x~1.0.0/a") + ps2 := MustSchemaID("x~1.0.0/b") + type args struct { old *Schema new *Schema @@ -20,6 +23,7 @@ func TestSchemaDiffFrom(t *testing.T) { name: "diff", args: args{ old: &Schema{ + id: ps1, groups: &SchemaGroupList{groups: []*SchemaGroup{ {id: "a", fields: []*SchemaField{ {id: "aa", propertyType: ValueTypeString}, // deleted @@ -30,6 +34,7 @@ func TestSchemaDiffFrom(t *testing.T) { }}, }, new: &Schema{ + id: ps2, groups: &SchemaGroupList{groups: []*SchemaGroup{ {id: "a", fields: []*SchemaField{ {id: "ab", propertyType: ValueTypeNumber}, // type changed @@ -43,6 +48,8 @@ func TestSchemaDiffFrom(t *testing.T) { }, }, want: SchemaDiff{ + From: ps1, + To: ps2, Deleted: []SchemaDiffDeleted{ {SchemaGroup: "a", Field: "aa"}, }, @@ -60,6 +67,7 @@ func TestSchemaDiffFrom(t *testing.T) { name: "no diff", args: args{ old: &Schema{ + id: ps1, groups: &SchemaGroupList{groups: []*SchemaGroup{ {id: "a", fields: []*SchemaField{ {id: "aa", propertyType: ValueTypeNumber}, @@ -67,6 +75,7 @@ func TestSchemaDiffFrom(t *testing.T) { }}, }, new: &Schema{ + id: ps2, groups: &SchemaGroupList{groups: []*SchemaGroup{ {id: "a", fields: []*SchemaField{ {id: "aa", propertyType: ValueTypeNumber}, @@ -77,7 +86,10 @@ func TestSchemaDiffFrom(t *testing.T) { }}, }, }, - want: SchemaDiff{}, + want: SchemaDiff{ + From: ps1, + To: ps2, + }, }, { name: "same schemas", @@ -85,7 +97,10 @@ func TestSchemaDiffFrom(t *testing.T) { old: testSchema1, new: testSchema1, }, - want: SchemaDiff{}, + want: SchemaDiff{ + From: testSchema1.ID(), + To: testSchema1.ID(), + }, }, { name: "nil", @@ -101,7 +116,9 @@ func TestSchemaDiffFrom(t *testing.T) { old: nil, new: testSchema1, }, - want: SchemaDiff{}, + want: SchemaDiff{ + To: testSchema1.ID(), + }, }, { name: "new nil", @@ -109,7 +126,9 @@ func TestSchemaDiffFrom(t *testing.T) { old: testSchema1, new: nil, }, - want: SchemaDiff{}, + want: SchemaDiff{ + From: testSchema1.ID(), + }, }, } @@ -121,6 +140,8 @@ func TestSchemaDiffFrom(t *testing.T) { } func TestSchemaDiffFromProperty(t *testing.T) { + ps := MustSchemaID("x~1.0.0/a") + type args struct { old *Property new *Schema @@ -135,6 +156,7 @@ func TestSchemaDiffFromProperty(t *testing.T) { args: args{ old: testProperty1, new: &Schema{ + id: ps, groups: &SchemaGroupList{groups: []*SchemaGroup{ {id: testSchemaGroup1.ID(), fields: []*SchemaField{ {id: testSchemaField1.ID(), propertyType: ValueTypeNumber}, // type changed @@ -146,6 +168,8 @@ func TestSchemaDiffFromProperty(t *testing.T) { }, }, want: SchemaDiff{ + From: testProperty1.Schema(), + To: ps, Deleted: nil, Moved: []SchemaDiffMoved{ { @@ -165,7 +189,10 @@ func TestSchemaDiffFromProperty(t *testing.T) { old: testProperty1, new: testSchema1, }, - want: SchemaDiff{}, + want: SchemaDiff{ + From: testProperty1.Schema(), + To: testSchema1.ID(), + }, }, { name: "nil", @@ -181,7 +208,9 @@ func TestSchemaDiffFromProperty(t *testing.T) { old: nil, new: testSchema1, }, - want: SchemaDiff{}, + want: SchemaDiff{ + To: testSchema1.ID(), + }, }, { name: "new nil", @@ -189,7 +218,9 @@ func TestSchemaDiffFromProperty(t *testing.T) { old: testProperty1, new: nil, }, - want: SchemaDiff{}, + want: SchemaDiff{ + From: testProperty1.Schema(), + }, }, } @@ -206,14 +237,14 @@ func TestSchemaDiff_Migrate(t *testing.T) { tests := []struct { name string - target SchemaDiff + target *SchemaDiff args *Property want bool wantProperty *Property }{ { name: "deleted and type changed", - target: SchemaDiff{ + target: &SchemaDiff{ Deleted: []SchemaDiffDeleted{ {SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, }, @@ -259,7 +290,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { }, { name: "moved", - target: SchemaDiff{ + target: &SchemaDiff{ Moved: []SchemaDiffMoved{ { From: SchemaFieldPointer{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, @@ -296,7 +327,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { }, { name: "moved and type changed", - target: SchemaDiff{ + target: &SchemaDiff{ Moved: []SchemaDiffMoved{ { From: SchemaFieldPointer{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, @@ -338,7 +369,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { }, { name: "group -> list", - target: SchemaDiff{ + target: &SchemaDiff{ Moved: []SchemaDiffMoved{ { From: SchemaFieldPointer{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, @@ -368,7 +399,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { }, { name: "list -> group", - target: SchemaDiff{ + target: &SchemaDiff{ Moved: []SchemaDiffMoved{ { From: SchemaFieldPointer{SchemaGroup: testGroup2.SchemaGroup(), Field: testField2.Field()}, @@ -406,20 +437,27 @@ func TestSchemaDiff_Migrate(t *testing.T) { }, { name: "empty", - target: SchemaDiff{}, + target: &SchemaDiff{}, args: testProperty1, want: false, wantProperty: testProperty1, }, { name: "nil property", - target: SchemaDiff{ + target: &SchemaDiff{ Deleted: []SchemaDiffDeleted{{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}}, }, args: nil, want: false, wantProperty: nil, }, + { + name: "nil", + target: nil, + args: nil, + want: false, + wantProperty: nil, + }, } for _, tt := range tests { @@ -429,3 +467,35 @@ func TestSchemaDiff_Migrate(t *testing.T) { }) } } + +func TestSchemaDiff_IsEmpty(t *testing.T) { + tests := []struct { + name string + target *SchemaDiff + want bool + }{ + { + name: "present", + target: &SchemaDiff{ + Deleted: []SchemaDiffDeleted{{SchemaGroup: "", Field: ""}}, + }, + want: false, + }, + { + name: "empty", + target: nil, + want: true, + }, + { + name: "nil", + target: nil, + want: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.IsEmpty()) + }) + } +} From 278ebf1b3fd8cd02ceb160a59d79879f66290e62 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 15 Dec 2021 16:07:22 +0900 Subject: [PATCH 39/55] add schema loader initializers --- pkg/property/loader.go | 14 ++++++++++++++ pkg/property/schema_list.go | 17 +++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/pkg/property/loader.go b/pkg/property/loader.go index f2bf3280..42220487 100644 --- a/pkg/property/loader.go +++ b/pkg/property/loader.go @@ -43,3 +43,17 @@ func LoaderFromMap(data map[id.PropertyID]*Property) Loader { return res, nil } } + +func SchemaLoaderFromMap(data map[id.PropertySchemaID]*Schema) SchemaLoader { + return func(ctx context.Context, ids ...id.PropertySchemaID) (SchemaList, error) { + res := make([]*Schema, 0, len(ids)) + for _, i := range ids { + if d, ok := data[i]; ok { + res = append(res, d) + } else { + res = append(res, nil) + } + } + return res, nil + } +} diff --git a/pkg/property/schema_list.go b/pkg/property/schema_list.go index 8666f60c..526eac1b 100644 --- a/pkg/property/schema_list.go +++ b/pkg/property/schema_list.go @@ -4,10 +4,23 @@ import "github.com/reearth/reearth-backend/pkg/id" type SchemaList []*Schema +func (l SchemaList) Find(psid SchemaID) *Schema { + for _, s := range l { + if s.ID().Equal(psid) { + return s + } + } + return nil +} + func (l SchemaList) Map() SchemaMap { return SchemaMapFrom(l) } +func (l SchemaList) Loader() SchemaLoader { + return SchemaLoaderFromMap(l.Map()) +} + type SchemaMap map[id.PropertySchemaID]*Schema func SchemaMapFrom(l []*Schema) SchemaMap { @@ -63,3 +76,7 @@ func (m SchemaMap) Merge(m2 SchemaMap) SchemaMap { return m3 } + +func (m SchemaMap) Loader() SchemaLoader { + return SchemaLoaderFromMap(m) +} From 5ced283772bbdc7bb9ec543ca688ec37e62bc2cf Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 15 Dec 2021 17:38:36 +0900 Subject: [PATCH 40/55] refactor and add nil check to plugin --- pkg/plugin/id.go | 12 +++++++++++ pkg/plugin/plugin.go | 49 ++++++++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 18 deletions(-) create mode 100644 pkg/plugin/id.go diff --git a/pkg/plugin/id.go b/pkg/plugin/id.go new file mode 100644 index 00000000..556bcc72 --- /dev/null +++ b/pkg/plugin/id.go @@ -0,0 +1,12 @@ +package plugin + +import "github.com/reearth/reearth-backend/pkg/id" + +type ID = id.PluginID +type ExtensionID = id.PluginExtensionID + +var NewID = id.NewPluginID +var MustID = id.MustPluginID +var IDFrom = id.PluginIDFrom +var IDFromRef = id.PluginIDFromRef +var ExtensionIDFromRef = id.PluginExtensionIDFromRef diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index 4757f605..0a1d0a15 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -6,53 +6,64 @@ import ( "github.com/reearth/reearth-backend/pkg/id" ) -// Plugin _ type Plugin struct { - id id.PluginID + id ID name i18n.String author string description i18n.String repositoryURL string - extensions map[id.PluginExtensionID]*Extension - extensionOrder []id.PluginExtensionID + extensions map[ExtensionID]*Extension + extensionOrder []ExtensionID schema *id.PropertySchemaID } -// ID _ -func (p *Plugin) ID() id.PluginID { +func (p *Plugin) ID() ID { + if p == nil { + return ID{} + } return p.id } -// Version _ func (p *Plugin) Version() semver.Version { + if p == nil { + return semver.Version{} + } return p.id.Version() } -// Name _ func (p *Plugin) Name() i18n.String { + if p == nil { + return nil + } return p.name.Copy() } -// Author _ func (p *Plugin) Author() string { + if p == nil { + return "" + } return p.author } -// Description _ func (p *Plugin) Description() i18n.String { + if p == nil { + return nil + } return p.description.Copy() } -// RepositoryURL _ func (p *Plugin) RepositoryURL() string { + if p == nil { + return "" + } return p.repositoryURL } -// Extensions _ func (p *Plugin) Extensions() []*Extension { - if p.extensionOrder == nil { - return []*Extension{} + if p == nil { + return nil } + list := make([]*Extension, 0, len(p.extensions)) for _, id := range p.extensionOrder { list = append(list, p.extensions[id]) @@ -60,7 +71,7 @@ func (p *Plugin) Extensions() []*Extension { return list } -func (p *Plugin) Extension(id id.PluginExtensionID) *Extension { +func (p *Plugin) Extension(id ExtensionID) *Extension { if p == nil { return nil } @@ -72,9 +83,12 @@ func (p *Plugin) Extension(id id.PluginExtensionID) *Extension { return nil } -// Schema _ func (p *Plugin) Schema() *id.PropertySchemaID { - return p.schema + if p == nil { + return nil + } + + return p.schema.CopyRef() } func (p *Plugin) PropertySchemas() []id.PropertySchemaID { @@ -96,7 +110,6 @@ func (p *Plugin) Rename(name i18n.String) { p.name = name.Copy() } -// SetDescription _ func (p *Plugin) SetDescription(des i18n.String) { p.description = des.Copy() } From 256c9a93ef3e30847031624a98eeb3e8125e7714 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 15 Dec 2021 17:39:06 +0900 Subject: [PATCH 41/55] impl plugin/manifest.Diff --- pkg/plugin/manifest/diff.go | 70 +++++++++++++ pkg/plugin/manifest/diff_test.go | 167 +++++++++++++++++++++++++++++++ pkg/plugin/manifest/manifest.go | 15 ++- 3 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 pkg/plugin/manifest/diff.go create mode 100644 pkg/plugin/manifest/diff_test.go diff --git a/pkg/plugin/manifest/diff.go b/pkg/plugin/manifest/diff.go new file mode 100644 index 00000000..a0a93c51 --- /dev/null +++ b/pkg/plugin/manifest/diff.go @@ -0,0 +1,70 @@ +package manifest + +import ( + "github.com/reearth/reearth-backend/pkg/id" + "github.com/reearth/reearth-backend/pkg/plugin" + "github.com/reearth/reearth-backend/pkg/property" +) + +type Diff struct { + From plugin.ID + To plugin.ID + PropertySchemaDiff property.SchemaDiff + PropertySchemaDeleted bool + DeletedExtensions []DiffExtensionDeleted + UpdatedExtensions []DiffExtensionUpdated +} + +type DiffExtensionUpdated struct { + ExtensionID plugin.ExtensionID + OldType plugin.ExtensionType + NewType plugin.ExtensionType + PropertySchemaDiff property.SchemaDiff +} + +type DiffExtensionDeleted struct { + ExtensionID plugin.ExtensionID + PropertySchemaID id.PropertySchemaID +} + +func DiffFrom(old, new Manifest) (d Diff) { + d.From = old.Plugin.ID() + d.To = new.Plugin.ID() + + oldsid, newsid := old.Plugin.Schema(), new.Plugin.Schema() + if oldsid != nil && newsid == nil { + d.PropertySchemaDiff.From = *oldsid + d.PropertySchemaDeleted = true + } else if oldsid != nil && newsid != nil { + d.PropertySchemaDiff = property.SchemaDiffFrom(old.PropertySchema(*oldsid), old.PropertySchema(*newsid)) + } + + for _, e := range old.Plugin.Extensions() { + ne := new.Plugin.Extension(e.ID()) + if ne == nil { + d.DeletedExtensions = append(d.DeletedExtensions, DiffExtensionDeleted{ + ExtensionID: e.ID(), + PropertySchemaID: e.Schema(), + }) + continue + } + + oldps, newps := old.PropertySchema(e.Schema()), new.PropertySchema(ne.Schema()) + diff := DiffExtensionUpdated{ + ExtensionID: e.ID(), + OldType: e.Type(), + NewType: ne.Type(), + PropertySchemaDiff: property.SchemaDiffFrom(oldps, newps), + } + + if diff.OldType != diff.NewType || !diff.PropertySchemaDiff.IsEmpty() { + d.UpdatedExtensions = append(d.UpdatedExtensions, diff) + } + } + + return +} + +func (d *Diff) IsEmpty() bool { + return d == nil || len(d.DeletedExtensions) == 0 && len(d.UpdatedExtensions) == 0 && d.PropertySchemaDiff.IsEmpty() && !d.PropertySchemaDeleted +} diff --git a/pkg/plugin/manifest/diff_test.go b/pkg/plugin/manifest/diff_test.go new file mode 100644 index 00000000..9e56197d --- /dev/null +++ b/pkg/plugin/manifest/diff_test.go @@ -0,0 +1,167 @@ +package manifest + +import ( + "testing" + + "github.com/reearth/reearth-backend/pkg/id" + "github.com/reearth/reearth-backend/pkg/plugin" + "github.com/reearth/reearth-backend/pkg/property" + "github.com/stretchr/testify/assert" +) + +func TestDiffFrom(t *testing.T) { + oldp := id.MustPluginID("aaaaaa~1.0.0") + newp := id.MustPluginID("aaaaaa~1.1.0") + oldps := id.MustPropertySchemaID("aaaaaa~1.0.0/_") + olde1ps := id.MustPropertySchemaID("aaaaaa~1.0.0/a") + olde2ps := id.MustPropertySchemaID("aaaaaa~1.0.0/b") + olde3ps := id.MustPropertySchemaID("aaaaaa~1.0.0/c") + olde4ps := id.MustPropertySchemaID("aaaaaa~1.0.0/d") + olde5ps := id.MustPropertySchemaID("aaaaaa~1.0.0/e") + newe1ps := id.MustPropertySchemaID("aaaaaa~1.1.0/a") + old := Manifest{ + Plugin: plugin.New().ID(oldp).Schema(&oldps).Extensions([]*plugin.Extension{ + plugin.NewExtension().ID("a").Schema(olde1ps).Type(plugin.ExtensionTypeBlock).MustBuild(), + plugin.NewExtension().ID("b").Schema(olde2ps).MustBuild(), // deleted + plugin.NewExtension().ID("c").Schema(olde3ps).Type(plugin.ExtensionTypeBlock).MustBuild(), + plugin.NewExtension().ID("d").Schema(olde4ps).Type(plugin.ExtensionTypeBlock).MustBuild(), + plugin.NewExtension().ID("e").Schema(olde5ps).Type(plugin.ExtensionTypeBlock).MustBuild(), + }).MustBuild(), + Schema: property.NewSchema().ID(oldps).MustBuild(), + ExtensionSchema: []*property.Schema{ + property.NewSchema().ID(olde1ps).MustBuild(), + property.NewSchema().ID(olde2ps).MustBuild(), + property.NewSchema().ID(olde3ps).MustBuild(), + property.NewSchema().ID(olde4ps).MustBuild(), + property.NewSchema().ID(olde5ps).Groups([]*property.SchemaGroup{ + property.NewSchemaGroup().ID("x").Fields([]*property.SchemaField{ + property.NewSchemaField().ID("y").Type(property.ValueTypeString).MustBuild(), + }).MustBuild(), // updated + }).MustBuild(), + }, + } + new := Manifest{ + Plugin: plugin.New().ID(newp).Extensions([]*plugin.Extension{ + plugin.NewExtension().ID("a").Schema(newe1ps).Type(plugin.ExtensionTypePrimitive).MustBuild(), // updated + plugin.NewExtension().ID("c").Schema(olde3ps).Type(plugin.ExtensionTypeBlock).MustBuild(), // same + plugin.NewExtension().ID("d").Schema(olde4ps).Type(plugin.ExtensionTypeBlock).MustBuild(), // property schema update + plugin.NewExtension().ID("e").Schema(olde5ps).Type(plugin.ExtensionTypeBlock).MustBuild(), // property schema update + }).MustBuild(), + ExtensionSchema: []*property.Schema{ + property.NewSchema().ID(newe1ps).MustBuild(), + property.NewSchema().ID(olde3ps).MustBuild(), + property.NewSchema().ID(olde4ps).Groups([]*property.SchemaGroup{ + property.NewSchemaGroup().ID("x").MustBuild(), // added + }).MustBuild(), + property.NewSchema().ID(olde5ps).Groups([]*property.SchemaGroup{ + property.NewSchemaGroup().ID("x").Fields([]*property.SchemaField{ + property.NewSchemaField().ID("y").Type(property.ValueTypeBool).MustBuild(), + }).MustBuild(), // updated + }).MustBuild(), + }, + } + + type args struct { + old Manifest + new Manifest + } + tests := []struct { + name string + args args + want Diff + }{ + { + name: "diff", + args: args{old: old, new: new}, + want: Diff{ + From: oldp, + To: newp, + PropertySchemaDiff: property.SchemaDiff{From: oldps}, + PropertySchemaDeleted: true, + DeletedExtensions: []DiffExtensionDeleted{{ExtensionID: "b", PropertySchemaID: olde2ps}}, + UpdatedExtensions: []DiffExtensionUpdated{ + { + ExtensionID: "a", + OldType: plugin.ExtensionTypeBlock, + NewType: plugin.ExtensionTypePrimitive, + PropertySchemaDiff: property.SchemaDiff{From: olde1ps, To: newe1ps}, + }, + { + ExtensionID: "e", + OldType: plugin.ExtensionTypeBlock, + NewType: plugin.ExtensionTypeBlock, + PropertySchemaDiff: property.SchemaDiff{ + From: olde5ps, + To: olde5ps, + TypeChanged: []property.SchemaDiffTypeChanged{ + {SchemaFieldPointer: property.SchemaFieldPointer{SchemaGroup: "x", Field: "y"}, NewType: property.ValueTypeBool}, + }, + }, + }, + }, + }, + }, + { + name: "same", + args: args{ + old: old, + new: old, + }, + want: Diff{ + From: oldp, + To: oldp, + PropertySchemaDiff: property.SchemaDiff{From: oldps, To: oldps}, + }, + }, + { + name: "nil", + args: args{}, + want: Diff{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, DiffFrom(tt.args.old, tt.args.new)) + }) + } +} + +func TestDiff_IsEmpty(t *testing.T) { + tests := []struct { + name string + target *Diff + want bool + }{ + { + name: "presemt", + target: &Diff{ + PropertySchemaDeleted: true, + }, + want: false, + }, + { + name: "empty", + target: &Diff{}, + want: true, + }, + { + name: "empty2", + target: &Diff{ + From: id.MustPluginID("a~1.0.0"), + }, + want: true, + }, + { + name: "nil", + target: nil, + want: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.IsEmpty()) + }) + } +} diff --git a/pkg/plugin/manifest/manifest.go b/pkg/plugin/manifest/manifest.go index 32f5ab71..9098590c 100644 --- a/pkg/plugin/manifest/manifest.go +++ b/pkg/plugin/manifest/manifest.go @@ -1,19 +1,30 @@ package manifest import ( + "github.com/reearth/reearth-backend/pkg/id" "github.com/reearth/reearth-backend/pkg/plugin" "github.com/reearth/reearth-backend/pkg/property" ) type Manifest struct { Plugin *plugin.Plugin - ExtensionSchema []*property.Schema + ExtensionSchema property.SchemaList Schema *property.Schema } -func (m Manifest) PropertySchemas() []*property.Schema { +func (m Manifest) PropertySchemas() property.SchemaList { if m.Schema == nil { return append([]*property.Schema{}, m.ExtensionSchema...) } return append(m.ExtensionSchema, m.Schema) } + +func (m Manifest) PropertySchema(psid id.PropertySchemaID) *property.Schema { + if psid.IsNil() { + return nil + } + if m.Schema != nil && psid.Equal(m.Schema.ID()) { + return m.Schema + } + return m.ExtensionSchema.Find(psid) +} From 49b53de5d17ab05904246d4778e08937ddbfc3b7 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Thu, 23 Dec 2021 16:35:33 +0900 Subject: [PATCH 42/55] add property.SchemaDiff.IsPropertySchemaChanged --- pkg/property/diff.go | 4 +++ pkg/property/diff_test.go | 56 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/pkg/property/diff.go b/pkg/property/diff.go index 36a2bf15..27194068 100644 --- a/pkg/property/diff.go +++ b/pkg/property/diff.go @@ -96,3 +96,7 @@ func (d *SchemaDiff) Migrate(p *Property) (res bool) { func (d *SchemaDiff) IsEmpty() bool { return d == nil || len(d.Deleted) == 0 && len(d.Moved) == 0 && len(d.TypeChanged) == 0 } + +func (d *SchemaDiff) IsPropertySchemaChanged() bool { + return d != nil && !d.From.Equal(d.To) +} diff --git a/pkg/property/diff_test.go b/pkg/property/diff_test.go index 50f94723..d82fc3d4 100644 --- a/pkg/property/diff_test.go +++ b/pkg/property/diff_test.go @@ -3,6 +3,7 @@ package property import ( "testing" + "github.com/reearth/reearth-backend/pkg/id" "github.com/stretchr/testify/assert" ) @@ -499,3 +500,58 @@ func TestSchemaDiff_IsEmpty(t *testing.T) { }) } } + +func TestSchemaDiff_IsPropertySchemaChanged(t *testing.T) { + tests := []struct { + name string + target *SchemaDiff + want bool + }{ + { + name: "changed1", + target: &SchemaDiff{ + From: id.MustPropertySchemaID("a~1.0.0/a"), + To: id.MustPropertySchemaID("a~1.0.1/a"), + }, + want: true, + }, + { + name: "changed2", + target: &SchemaDiff{ + From: id.MustPropertySchemaID("a~1.0.0/a"), + }, + want: true, + }, + { + name: "changed3", + target: &SchemaDiff{ + To: id.MustPropertySchemaID("a~1.0.0/a"), + }, + want: true, + }, + { + name: "unchanged1", + target: &SchemaDiff{ + From: id.MustPropertySchemaID("a~1.0.0/a"), + To: id.MustPropertySchemaID("a~1.0.0/a"), + }, + want: false, + }, + { + name: "empty", + target: &SchemaDiff{}, + want: false, + }, + { + name: "nil", + target: nil, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.IsPropertySchemaChanged()) + }) + } +} From 9d15e8977ed9fb63f4ba5cbea78eaed45a9322b6 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Thu, 23 Dec 2021 16:50:14 +0900 Subject: [PATCH 43/55] add property.List.IDs --- pkg/property/list.go | 29 +++++++++++++--- pkg/property/list_test.go | 72 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 5 deletions(-) diff --git a/pkg/property/list.go b/pkg/property/list.go index 9fe0af64..d3d887c9 100644 --- a/pkg/property/list.go +++ b/pkg/property/list.go @@ -8,17 +8,36 @@ import ( type List []*Property -func (l List) Schemas() []id.PropertySchemaID { - schemas := make([]id.PropertySchemaID, 0, len(l)) - m := map[id.PropertySchemaID]struct{}{} +func (l List) IDs() []ID { + ids := make([]ID, 0, len(l)) + m := map[ID]struct{}{} for _, p := range l { - s := p.Schema() + s := p.ID() if _, ok := m[s]; ok { continue } - schemas = append(schemas, s) + ids = append(ids, s) m[s] = struct{}{} } + return ids +} + +func (l List) Schemas() []SchemaID { + schemas := make([]SchemaID, 0, len(l)) + for _, p := range l { + s := p.Schema() + skip := false + for _, ss := range schemas { + if ss.Equal(s) { + skip = true + break + } + } + if skip { + continue + } + schemas = append(schemas, s) + } return schemas } diff --git a/pkg/property/list_test.go b/pkg/property/list_test.go index e7f20c1e..ee108f7c 100644 --- a/pkg/property/list_test.go +++ b/pkg/property/list_test.go @@ -14,6 +14,78 @@ var ( p2 = New().NewID().Scene(id.NewSceneID()).Schema(id.MustPropertySchemaID("xx~1.0.0/aa")).Items([]Item{InitItemFrom(sg)}).MustBuild() ) +func TestList_IDs(t *testing.T) { + p1 := NewID() + p2 := NewID() + + tests := []struct { + name string + target List + want []ID + }{ + { + name: "ok", + target: List{&Property{id: p1}, &Property{id: p2}, &Property{id: p1}}, + want: []ID{p1, p2}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.IDs()) + }) + } +} + +func TestList_Schemas(t *testing.T) { + ps1 := MustSchemaID("x~1.0.0/a") + ps2 := MustSchemaID("x~1.0.0/b") + + tests := []struct { + name string + target List + want []SchemaID + }{ + { + name: "ok", + target: List{&Property{schema: ps1}, &Property{schema: ps2}, &Property{schema: ps1}}, + want: []SchemaID{ps1, ps2}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Schemas()) + }) + } +} + +func TestList_Map(t *testing.T) { + p1 := NewID() + p2 := NewID() + + tests := []struct { + name string + target List + want Map + }{ + { + name: "ok", + target: List{&Property{id: p1}, &Property{id: p2}, &Property{id: p1}}, + want: Map{ + p1: &Property{id: p1}, + p2: &Property{id: p2}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Map()) + }) + } +} + func TestMap_Add(t *testing.T) { testCases := []struct { Name string From 131b1d7afd2b157699870430f037716bd336f1ca Mon Sep 17 00:00:00 2001 From: rot1024 Date: Thu, 23 Dec 2021 17:04:44 +0900 Subject: [PATCH 44/55] rename property.SchemaDiff.IsPropertySchemaChanged --- pkg/property/diff.go | 2 +- pkg/property/diff_test.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/property/diff.go b/pkg/property/diff.go index 27194068..23459a2a 100644 --- a/pkg/property/diff.go +++ b/pkg/property/diff.go @@ -97,6 +97,6 @@ func (d *SchemaDiff) IsEmpty() bool { return d == nil || len(d.Deleted) == 0 && len(d.Moved) == 0 && len(d.TypeChanged) == 0 } -func (d *SchemaDiff) IsPropertySchemaChanged() bool { +func (d *SchemaDiff) IsIDChanged() bool { return d != nil && !d.From.Equal(d.To) } diff --git a/pkg/property/diff_test.go b/pkg/property/diff_test.go index d82fc3d4..02605b8d 100644 --- a/pkg/property/diff_test.go +++ b/pkg/property/diff_test.go @@ -484,7 +484,7 @@ func TestSchemaDiff_IsEmpty(t *testing.T) { }, { name: "empty", - target: nil, + target: &SchemaDiff{}, want: true, }, { @@ -501,7 +501,7 @@ func TestSchemaDiff_IsEmpty(t *testing.T) { } } -func TestSchemaDiff_IsPropertySchemaChanged(t *testing.T) { +func TestSchemaDiff_IsIDChanged(t *testing.T) { tests := []struct { name string target *SchemaDiff @@ -551,7 +551,7 @@ func TestSchemaDiff_IsPropertySchemaChanged(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.want, tt.target.IsPropertySchemaChanged()) + assert.Equal(t, tt.want, tt.target.IsIDChanged()) }) } } From fd20d7f8790d759aba04b662c915b34a7a81dd4a Mon Sep 17 00:00:00 2001 From: rot1024 Date: Thu, 23 Dec 2021 17:07:08 +0900 Subject: [PATCH 45/55] add DeletedPropertySchemas and PropertySchmaDiffs to manifest.Diff --- pkg/plugin/manifest/diff.go | 34 +++++++++++++ pkg/plugin/manifest/diff_test.go | 82 ++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/pkg/plugin/manifest/diff.go b/pkg/plugin/manifest/diff.go index a0a93c51..2d9b2b12 100644 --- a/pkg/plugin/manifest/diff.go +++ b/pkg/plugin/manifest/diff.go @@ -68,3 +68,37 @@ func DiffFrom(old, new Manifest) (d Diff) { func (d *Diff) IsEmpty() bool { return d == nil || len(d.DeletedExtensions) == 0 && len(d.UpdatedExtensions) == 0 && d.PropertySchemaDiff.IsEmpty() && !d.PropertySchemaDeleted } + +func (d Diff) DeletedPropertySchemas() []id.PropertySchemaID { + s := make([]id.PropertySchemaID, 0, len(d.DeletedExtensions)+1) + if d.PropertySchemaDeleted { + s = append(s, d.PropertySchemaDiff.From) + } + for _, e := range d.DeletedExtensions { + skip := false + for _, ss := range s { + if ss.Equal(e.PropertySchemaID) { + skip = true + break + } + } + if skip { + continue + } + s = append(s, e.PropertySchemaID) + } + return s +} + +func (d Diff) PropertySchmaDiffs() []property.SchemaDiff { + s := make([]property.SchemaDiff, 0, len(d.UpdatedExtensions)+1) + if !d.PropertySchemaDeleted && (!d.PropertySchemaDiff.IsEmpty() || d.PropertySchemaDiff.IsIDChanged()) { + s = append(s, d.PropertySchemaDiff) + } + for _, e := range d.UpdatedExtensions { + if !e.PropertySchemaDiff.IsEmpty() || e.PropertySchemaDiff.IsIDChanged() { + s = append(s, e.PropertySchemaDiff) + } + } + return s +} diff --git a/pkg/plugin/manifest/diff_test.go b/pkg/plugin/manifest/diff_test.go index 9e56197d..73d78ac6 100644 --- a/pkg/plugin/manifest/diff_test.go +++ b/pkg/plugin/manifest/diff_test.go @@ -165,3 +165,85 @@ func TestDiff_IsEmpty(t *testing.T) { }) } } + +func TestDiff_DeletedPropertySchemas(t *testing.T) { + ps1 := id.MustPropertySchemaID("a~1.0.0/a") + ps2 := id.MustPropertySchemaID("a~1.0.0/b") + tests := []struct { + name string + target Diff + want []id.PropertySchemaID + }{ + { + name: "ok", + target: Diff{ + PropertySchemaDiff: property.SchemaDiff{ + From: ps1, + }, + PropertySchemaDeleted: true, + DeletedExtensions: []DiffExtensionDeleted{ + {PropertySchemaID: ps2}, + {PropertySchemaID: ps2}, + }, + }, + want: []id.PropertySchemaID{ + ps1, + ps2, + }, + }, + { + name: "empty", + target: Diff{}, + want: []id.PropertySchemaID{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.DeletedPropertySchemas()) + }) + } +} + +func TestDiff_PropertySchmaDiffs(t *testing.T) { + ps1 := id.MustPropertySchemaID("a~1.0.0/a") + ps2 := id.MustPropertySchemaID("a~1.0.0/b") + tests := []struct { + name string + target Diff + want []property.SchemaDiff + }{ + { + name: "ok", + target: Diff{ + PropertySchemaDiff: property.SchemaDiff{ + From: ps1, + }, + UpdatedExtensions: []DiffExtensionUpdated{ + {PropertySchemaDiff: property.SchemaDiff{ + From: ps2, + }}, + }, + }, + want: []property.SchemaDiff{ + { + From: ps1, + }, + { + From: ps2, + }, + }, + }, + { + name: "empty", + target: Diff{}, + want: []property.SchemaDiff{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.PropertySchmaDiffs()) + }) + } +} From 9a1b631e9ff7d793b29e4d4ad63537d24f1ceb18 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Thu, 23 Dec 2021 17:14:52 +0900 Subject: [PATCH 46/55] update scene.PluginSystem.Upgrade --- pkg/scene/plugin.go | 4 -- pkg/scene/plugin_system.go | 29 +++++------ pkg/scene/plugin_system_test.go | 69 +++++++++++++++++++-------- pkg/scene/sceneops/plugin_migrator.go | 2 +- 4 files changed, 66 insertions(+), 38 deletions(-) diff --git a/pkg/scene/plugin.go b/pkg/scene/plugin.go index 63e863d2..c15ef56e 100644 --- a/pkg/scene/plugin.go +++ b/pkg/scene/plugin.go @@ -4,13 +4,11 @@ import ( "github.com/reearth/reearth-backend/pkg/id" ) -// Plugin _ type Plugin struct { plugin id.PluginID property *id.PropertyID } -// NewPlugin _ func NewPlugin(plugin id.PluginID, property *id.PropertyID) *Plugin { if property != nil { property2 := *property @@ -22,12 +20,10 @@ func NewPlugin(plugin id.PluginID, property *id.PropertyID) *Plugin { } } -// Plugin _ func (s Plugin) Plugin() id.PluginID { return s.plugin } -// Property _ func (s Plugin) Property() *id.PropertyID { property := s.property if property != nil { diff --git a/pkg/scene/plugin_system.go b/pkg/scene/plugin_system.go index e0c756cf..a10a6aa9 100644 --- a/pkg/scene/plugin_system.go +++ b/pkg/scene/plugin_system.go @@ -4,12 +4,10 @@ import ( "github.com/reearth/reearth-backend/pkg/id" ) -// PluginSystem _ type PluginSystem struct { plugins []*Plugin } -// NewPluginSystem _ func NewPluginSystem(p []*Plugin) *PluginSystem { if p == nil { return &PluginSystem{plugins: []*Plugin{}} @@ -34,12 +32,10 @@ func NewPluginSystem(p []*Plugin) *PluginSystem { return &PluginSystem{plugins: p2} } -// Plugins _ func (p *PluginSystem) Plugins() []*Plugin { return append([]*Plugin{}, p.plugins...) } -// Property _ func (p *PluginSystem) Property(id id.PluginID) *id.PropertyID { for _, p := range p.plugins { if p.plugin.Equal(id) { @@ -49,7 +45,6 @@ func (p *PluginSystem) Property(id id.PluginID) *id.PropertyID { return nil } -// Has _ func (p *PluginSystem) Has(id id.PluginID) bool { for _, p2 := range p.plugins { if p2.plugin.Equal(id) { @@ -59,7 +54,6 @@ func (p *PluginSystem) Has(id id.PluginID) bool { return false } -// HasPlugin _ func (p *PluginSystem) HasPlugin(id id.PluginID) bool { name := id.Name() for _, p2 := range p.plugins { @@ -70,7 +64,6 @@ func (p *PluginSystem) HasPlugin(id id.PluginID) bool { return false } -// Add _ func (p *PluginSystem) Add(sp *Plugin) { if sp == nil || p.Has(sp.plugin) || sp.plugin.Equal(id.OfficialPluginID) { return @@ -79,7 +72,6 @@ func (p *PluginSystem) Add(sp *Plugin) { p.plugins = append(p.plugins, &sp2) } -// Remove _ func (p *PluginSystem) Remove(pid id.PluginID) { if pid.Equal(id.OfficialPluginID) { return @@ -92,14 +84,23 @@ func (p *PluginSystem) Remove(pid id.PluginID) { } } -// Upgrade _ -func (p *PluginSystem) Upgrade(pid, newID id.PluginID) { - for i, p2 := range p.plugins { - if p2.plugin.Equal(id.OfficialPluginID) { +func (p *PluginSystem) Upgrade(pid, newpid id.PluginID, pr *id.PropertyID, deleteProperty bool) { + for i, pp := range p.plugins { + if pp.plugin.Equal(id.OfficialPluginID) { continue } - if p2.plugin.Equal(pid) { - p.plugins[i] = &Plugin{plugin: newID, property: p2.property} + if pp.plugin.Equal(pid) { + if newpid.IsNil() { + newpid = pp.plugin + } + newp := pp.property + if pr != nil { + newp = pr.CopyRef() + } + if deleteProperty { + newp = nil + } + p.plugins[i] = &Plugin{plugin: newpid, property: newp} return } } diff --git a/pkg/scene/plugin_system_test.go b/pkg/scene/plugin_system_test.go index e8acd920..d5dcd8bb 100644 --- a/pkg/scene/plugin_system_test.go +++ b/pkg/scene/plugin_system_test.go @@ -307,32 +307,63 @@ func TestPluginSystem_Remove(t *testing.T) { func TestPluginSystem_Upgrade(t *testing.T) { pid := id.MustPluginID("xxx~1.1.1") nid := id.MustPluginID("zzz~1.1.1") - pr := id.NewPropertyID().Ref() - testCases := []struct { - Name string - PID, NewID id.PluginID - PS, Expected *PluginSystem + pr1 := id.NewPropertyID().Ref() + pr2 := id.NewPropertyID().Ref() + + type args struct { + pid id.PluginID + newpid id.PluginID + pr *id.PropertyID + deleteProperty bool + } + tests := []struct { + name string + args args + target *PluginSystem + want *PluginSystem }{ { - Name: "upgrade official plugin", - PID: id.OfficialPluginID, - PS: NewPluginSystem([]*Plugin{NewPlugin(id.OfficialPluginID, pr)}), - Expected: NewPluginSystem([]*Plugin{NewPlugin(id.OfficialPluginID, pr)}), + name: "upgrade official plugin", + args: args{ + pid: id.OfficialPluginID, + }, + target: NewPluginSystem([]*Plugin{NewPlugin(id.OfficialPluginID, pr1)}), + want: NewPluginSystem([]*Plugin{NewPlugin(id.OfficialPluginID, pr1)}), }, { - Name: "upgrade a plugin", - PID: pid, - NewID: nid, - PS: NewPluginSystem([]*Plugin{NewPlugin(pid, pr)}), - Expected: NewPluginSystem([]*Plugin{NewPlugin(nid, pr)}), + name: "upgrade a plugin", + args: args{ + pid: pid, + newpid: nid, + }, + target: NewPluginSystem([]*Plugin{NewPlugin(pid, pr1)}), + want: NewPluginSystem([]*Plugin{NewPlugin(nid, pr1)}), + }, + { + name: "upgrade a property", + args: args{ + pid: pid, + pr: pr2, + }, + target: NewPluginSystem([]*Plugin{NewPlugin(pid, pr1)}), + want: NewPluginSystem([]*Plugin{NewPlugin(pid, pr2)}), + }, + { + name: "delete a property", + args: args{ + pid: pid, + deleteProperty: true, + }, + target: NewPluginSystem([]*Plugin{NewPlugin(pid, pr1)}), + want: NewPluginSystem([]*Plugin{NewPlugin(pid, nil)}), }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.Name, func(tt *testing.T) { + for _, tt := range tests { + tc := tt + t.Run(tc.name, func(tt *testing.T) { tt.Parallel() - tc.PS.Upgrade(tc.PID, tc.NewID) - assert.Equal(tt, tc.Expected, tc.PS) + tc.target.Upgrade(tc.args.pid, tc.args.newpid, tc.args.pr, tc.args.deleteProperty) + assert.Equal(tt, tc.want, tc.target) }) } } diff --git a/pkg/scene/sceneops/plugin_migrator.go b/pkg/scene/sceneops/plugin_migrator.go index cb3b68ae..7c2c3a51 100644 --- a/pkg/scene/sceneops/plugin_migrator.go +++ b/pkg/scene/sceneops/plugin_migrator.go @@ -101,7 +101,7 @@ func (s *PluginMigrator) MigratePlugins(ctx context.Context, sc *scene.Scene, ol } // シーンのプラグイン - sc.PluginSystem().Upgrade(oldPluginID, newPluginID) + sc.PluginSystem().Upgrade(oldPluginID, newPluginID, nil, false) for _, sp := range sc.PluginSystem().Plugins() { if sp.Plugin().Equal(newPluginID) && sp.Property() != nil { propertyIDs = append(propertyIDs, *sp.Property()) From 64cf1c0fec60c4c1a5b99a89913bb8ecc016d9bf Mon Sep 17 00:00:00 2001 From: rot1024 Date: Thu, 23 Dec 2021 17:23:13 +0900 Subject: [PATCH 47/55] add FindBySchema to repo.Property --- internal/infrastructure/memory/property.go | 24 +++++++ .../infrastructure/memory/property_test.go | 69 +++++++++++++++++++ internal/infrastructure/mongo/property.go | 28 ++++++-- internal/usecase/repo/property.go | 1 + 4 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 internal/infrastructure/memory/property_test.go diff --git a/internal/infrastructure/memory/property.go b/internal/infrastructure/memory/property.go index 38f25fcf..e36bd990 100644 --- a/internal/infrastructure/memory/property.go +++ b/internal/infrastructure/memory/property.go @@ -2,6 +2,7 @@ package memory import ( "context" + "sort" "sync" "github.com/reearth/reearth-backend/pkg/id" @@ -80,6 +81,29 @@ func (r *Property) FindLinkedAll(ctx context.Context, s id.SceneID) (property.Li return result, nil } +func (r *Property) FindBySchema(_ context.Context, schemas []id.PropertySchemaID, s id.SceneID) (property.List, error) { + r.lock.Lock() + defer r.lock.Unlock() + + result := property.List{} + for _, p := range r.data { + if p.Scene() != s { + continue + } + for _, s := range schemas { + if p.Schema().Equal(s) { + p2 := p + result = append(result, &p2) + break + } + } + } + sort.Slice(result, func(i, j int) bool { + return result[i].ID().ID().Compare(result[j].ID().ID()) < 0 + }) + return result, nil +} + func (r *Property) Save(ctx context.Context, p *property.Property) error { r.lock.Lock() defer r.lock.Unlock() diff --git a/internal/infrastructure/memory/property_test.go b/internal/infrastructure/memory/property_test.go new file mode 100644 index 00000000..a2841f7c --- /dev/null +++ b/internal/infrastructure/memory/property_test.go @@ -0,0 +1,69 @@ +package memory + +import ( + "context" + "testing" + + "github.com/reearth/reearth-backend/pkg/id" + "github.com/reearth/reearth-backend/pkg/property" + "github.com/stretchr/testify/assert" +) + +func TestProperty_FindBySchema(t *testing.T) { + p1 := id.NewPropertyID() + p2 := id.NewPropertyID() + p3 := id.NewPropertyID() + p4 := id.NewPropertyID() + p5 := id.NewPropertyID() + ps1 := id.MustPropertySchemaID("a~1.0.0/a") + ps2 := id.MustPropertySchemaID("a~1.0.0/b") + s1 := id.NewSceneID() + s2 := id.NewSceneID() + + type args struct { + in0 context.Context + schemas []id.PropertySchemaID + s id.SceneID + } + tests := []struct { + name string + target *Property + args args + want property.List + wantErr error + }{ + { + name: "found", + target: &Property{ + data: map[id.PropertyID]property.Property{ + p1: *property.New().ID(p1).Scene(s1).Schema(ps1).MustBuild(), + p2: *property.New().ID(p2).Scene(s1).Schema(ps2).MustBuild(), + p3: *property.New().ID(p3).Scene(s2).Schema(ps1).MustBuild(), + p4: *property.New().ID(p4).Scene(s2).Schema(ps2).MustBuild(), + p5: *property.New().ID(p5).Scene(s1).Schema(ps1).MustBuild(), + }, + }, + args: args{ + in0: nil, + schemas: []id.PropertySchemaID{ps1, ps2}, + s: s1, + }, + want: property.List{ + property.New().ID(p1).Scene(s1).Schema(ps1).MustBuild(), + property.New().ID(p2).Scene(s1).Schema(ps2).MustBuild(), + property.New().ID(p5).Scene(s1).Schema(ps1).MustBuild(), + }, + wantErr: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got, err := tt.target.FindBySchema(tt.args.in0, tt.args.schemas, tt.args.s) + assert.Equal(t, tt.wantErr, err) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/infrastructure/mongo/property.go b/internal/infrastructure/mongo/property.go index a879654b..815c41d4 100644 --- a/internal/infrastructure/mongo/property.go +++ b/internal/infrastructure/mongo/property.go @@ -30,12 +30,12 @@ func (r *propertyRepo) init() { } func (r *propertyRepo) FindByID(ctx context.Context, id2 id.PropertyID, f []id.SceneID) (*property.Property, error) { - filter := r.sceneFilter(bson.D{{Key: "id", Value: id.ID(id2).String()}}, f) + filter := r.sceneFilterD(bson.D{{Key: "id", Value: id.ID(id2).String()}}, f) return r.findOne(ctx, filter) } func (r *propertyRepo) FindByIDs(ctx context.Context, ids []id.PropertyID, f []id.SceneID) (property.List, error) { - filter := r.sceneFilter(bson.D{{Key: "id", Value: bson.D{{ + filter := r.sceneFilterD(bson.D{{Key: "id", Value: bson.D{{ Key: "$in", Value: id.PropertyIDToKeys(ids), }}}}, f) dst := make(property.List, 0, len(ids)) @@ -78,6 +78,14 @@ func (r *propertyRepo) FindByDataset(ctx context.Context, sid id.DatasetSchemaID return r.find(ctx, nil, filter) } +func (r *propertyRepo) FindBySchema(ctx context.Context, psids []id.PropertySchemaID, sid id.SceneID) (property.List, error) { + filter := bson.M{ + "schema": bson.M{"$in": id.PropertySchemaIDToKeys(psids)}, + "scene": sid.String(), + } + return r.find(ctx, nil, filter) +} + func (r *propertyRepo) Save(ctx context.Context, property *property.Property) error { doc, id := mongodoc.NewProperty(property) return r.client.SaveOne(ctx, id, doc) @@ -113,7 +121,7 @@ func (r *propertyRepo) RemoveByScene(ctx context.Context, sceneID id.SceneID) er return nil } -func (r *propertyRepo) find(ctx context.Context, dst property.List, filter bson.D) (property.List, error) { +func (r *propertyRepo) find(ctx context.Context, dst property.List, filter interface{}) (property.List, error) { c := mongodoc.PropertyConsumer{ Rows: dst, } @@ -123,7 +131,7 @@ func (r *propertyRepo) find(ctx context.Context, dst property.List, filter bson. return c.Rows, nil } -func (r *propertyRepo) findOne(ctx context.Context, filter bson.D) (*property.Property, error) { +func (r *propertyRepo) findOne(ctx context.Context, filter interface{}) (*property.Property, error) { dst := make(property.List, 0, 1) c := mongodoc.PropertyConsumer{ Rows: dst, @@ -134,7 +142,7 @@ func (r *propertyRepo) findOne(ctx context.Context, filter bson.D) (*property.Pr return c.Rows[0], nil } -// func (r *propertyRepo) paginate(ctx context.Context, filter bson.D, pagination *usecase.Pagination) (property.List, *usecase.PageInfo, error) { +// func (r *propertyRepo) paginate(ctx context.Context, filter interface{}, pagination *usecase.Pagination) (property.List, *usecase.PageInfo, error) { // var c propertyConsumer // pageInfo, err2 := r.client.Paginate(ctx, filter, pagination, &c) // if err2 != nil { @@ -158,7 +166,15 @@ func filterProperties(ids []id.PropertyID, rows property.List) property.List { return res } -func (*propertyRepo) sceneFilter(filter bson.D, scenes []id.SceneID) bson.D { +func (*propertyRepo) sceneFilter(filter bson.M, scenes []id.SceneID) bson.M { + if scenes == nil { + return filter + } + filter["scene"] = bson.M{"$in": id.SceneIDToKeys(scenes)} + return filter +} + +func (*propertyRepo) sceneFilterD(filter bson.D, scenes []id.SceneID) bson.D { if scenes == nil { return filter } diff --git a/internal/usecase/repo/property.go b/internal/usecase/repo/property.go index 469ea239..fbe95c8c 100644 --- a/internal/usecase/repo/property.go +++ b/internal/usecase/repo/property.go @@ -12,6 +12,7 @@ type Property interface { FindByIDs(context.Context, []id.PropertyID, []id.SceneID) (property.List, error) FindLinkedAll(context.Context, id.SceneID) (property.List, error) FindByDataset(context.Context, id.DatasetSchemaID, id.DatasetID) (property.List, error) + FindBySchema(context.Context, []id.PropertySchemaID, id.SceneID) (property.List, error) Save(context.Context, *property.Property) error SaveAll(context.Context, property.List) error Remove(context.Context, id.PropertyID) error From d89ecc7fabd9c1be8ccdeed89d5a497f86eb059b Mon Sep 17 00:00:00 2001 From: rot1024 Date: Thu, 23 Dec 2021 17:37:09 +0900 Subject: [PATCH 48/55] add IDs to layer.List --- pkg/layer/id.go | 27 +++++++++++++++++++++++++++ pkg/layer/list.go | 11 +++++++++++ pkg/layer/list_test.go | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 pkg/layer/id.go diff --git a/pkg/layer/id.go b/pkg/layer/id.go new file mode 100644 index 00000000..667037d6 --- /dev/null +++ b/pkg/layer/id.go @@ -0,0 +1,27 @@ +package layer + +import "github.com/reearth/reearth-backend/pkg/id" + +type ID = id.LayerID +type IDSet = id.LayerIDSet +type InfoboxFieldID = id.InfoboxFieldID +type InfoboxFIeldIDSet = id.InfoboxFieldIDSet +type SceneID = id.SceneID +type PluginID = id.PluginID +type PluginExtensionID = id.PluginExtensionID +type PropertyID = id.PropertyID +type PropertySchemaID = id.PropertySchemaID + +var NewID = id.NewLayerID +var MustID = id.MustLayerID +var IDFrom = id.LayerIDFrom +var IDFromRef = id.LayerIDFromRef +var IDFromRefID = id.LayerIDFromRefID +var NewIDSet = id.NewLayerIDSet + +var NewInfoboxFieldID = id.NewInfoboxFieldID +var MustInfoboxFieldID = id.MustInfoboxFieldID +var InfoboxFieldIDFrom = id.InfoboxFieldIDFrom +var InfoboxFieldIDFromRef = id.InfoboxFieldIDFromRef +var InfoboxFieldIDFromRefID = id.InfoboxFieldIDFromRefID +var NewInfoboxFIeldIDSet = id.NewInfoboxFieldIDSet diff --git a/pkg/layer/list.go b/pkg/layer/list.go index d6fb1b31..35e889a0 100644 --- a/pkg/layer/list.go +++ b/pkg/layer/list.go @@ -8,6 +8,17 @@ import ( type List []*Layer +func (ll List) IDs() *IDList { + if len(ll) == 0 { + return nil + } + ids := make([]ID, 0, len(ll)) + for _, l := range ll.Deref() { + ids = append(ids, l.ID()) + } + return NewIDList(ids) +} + func (ll List) Last() *Layer { if len(ll) == 0 { return nil diff --git a/pkg/layer/list_test.go b/pkg/layer/list_test.go index 398325dc..a14f5cf5 100644 --- a/pkg/layer/list_test.go +++ b/pkg/layer/list_test.go @@ -7,6 +7,38 @@ import ( "github.com/stretchr/testify/assert" ) +func TestList_IDs(t *testing.T) { + sid := id.NewSceneID() + l1 := NewID() + l2 := NewID() + + tests := []struct { + name string + target List + want *IDList + }{ + { + name: "ok", + target: List{ + New().ID(l1).Scene(sid).Item().MustBuild().LayerRef(), + New().ID(l2).Scene(sid).Group().MustBuild().LayerRef(), + }, + want: NewIDList([]ID{l1, l2}), + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.IDs()) + }) + } +} + func TestList_Remove(t *testing.T) { sid := id.NewSceneID() l1 := NewItem().NewID().Scene(sid).MustBuild() From 74dee499f077d89cee398225e5a03628516757df Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 12 Jan 2022 18:54:44 +0900 Subject: [PATCH 49/55] add Properties method to pkg/layer.List --- pkg/layer/list.go | 11 +++++++++++ pkg/layer/list_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/pkg/layer/list.go b/pkg/layer/list.go index 35e889a0..aff329b0 100644 --- a/pkg/layer/list.go +++ b/pkg/layer/list.go @@ -19,6 +19,17 @@ func (ll List) IDs() *IDList { return NewIDList(ids) } +func (ll List) Properties() []PropertyID { + if len(ll) == 0 { + return nil + } + ids := make([]PropertyID, 0, len(ll)) + for _, l := range ll.Deref() { + ids = append(ids, l.Properties()...) + } + return ids +} + func (ll List) Last() *Layer { if len(ll) == 0 { return nil diff --git a/pkg/layer/list_test.go b/pkg/layer/list_test.go index a14f5cf5..e756271a 100644 --- a/pkg/layer/list_test.go +++ b/pkg/layer/list_test.go @@ -39,6 +39,41 @@ func TestList_IDs(t *testing.T) { } } +func TestList_Properties(t *testing.T) { + sid := id.NewSceneID() + p1 := id.NewPropertyID() + p2 := id.NewPropertyID() + p3 := id.NewPropertyID() + + tests := []struct { + name string + target List + want []PropertyID + }{ + { + name: "ok", + target: List{ + New().NewID().Scene(sid).Property(&p1).Item().MustBuild().LayerRef(), + New().NewID().Scene(sid).Infobox(NewInfobox([]*InfoboxField{ + {property: p3}, + }, p2)).Group().MustBuild().LayerRef(), + }, + want: []PropertyID{p1, p2, p3}, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.target.Properties()) + }) + } +} + func TestList_Remove(t *testing.T) { sid := id.NewSceneID() l1 := NewItem().NewID().Scene(sid).MustBuild() From 87c94bbd299af563108c16ce159486783e092d7c Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 12 Jan 2022 19:07:55 +0900 Subject: [PATCH 50/55] refactor mongo and add indexes --- internal/infrastructure/mongo/layer.go | 44 +++++++++++++---------- internal/infrastructure/mongo/property.go | 2 +- internal/infrastructure/mongo/tag.go | 2 +- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/internal/infrastructure/mongo/layer.go b/internal/infrastructure/mongo/layer.go index 3ef8a8f0..c2d7bce5 100644 --- a/internal/infrastructure/mongo/layer.go +++ b/internal/infrastructure/mongo/layer.go @@ -24,21 +24,21 @@ func NewLayer(client *mongodoc.Client) repo.Layer { } func (r *layerRepo) init() { - i := r.client.CreateIndex(context.Background(), nil) + i := r.client.CreateIndex(context.Background(), []string{"scene", "group.layers"}) if len(i) > 0 { log.Infof("mongo: %s: index created: %s", "layer", i) } } func (r *layerRepo) FindByID(ctx context.Context, id id.LayerID, f []id.SceneID) (layer.Layer, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "id", Value: id.String()}, }, f) return r.findOne(ctx, filter) } func (r *layerRepo) FindByIDs(ctx context.Context, ids []id.LayerID, f []id.SceneID) (layer.List, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "id", Value: bson.D{ {Key: "$in", Value: id.LayerIDToKeys(ids)}, }}, @@ -59,14 +59,14 @@ func (r *layerRepo) FindAllByDatasetSchema(ctx context.Context, dsid id.DatasetS } func (r *layerRepo) FindItemByID(ctx context.Context, id id.LayerID, f []id.SceneID) (*layer.Item, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "id", Value: id.String()}, }, f) return r.findItemOne(ctx, filter) } func (r *layerRepo) FindItemByIDs(ctx context.Context, ids []id.LayerID, f []id.SceneID) (layer.ItemList, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "id", Value: bson.D{ {Key: "$in", Value: id.LayerIDToKeys(ids)}, }}, @@ -80,14 +80,14 @@ func (r *layerRepo) FindItemByIDs(ctx context.Context, ids []id.LayerID, f []id. } func (r *layerRepo) FindGroupByID(ctx context.Context, id id.LayerID, f []id.SceneID) (*layer.Group, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "id", Value: id.String()}, }, f) return r.findGroupOne(ctx, filter) } func (r *layerRepo) FindGroupByIDs(ctx context.Context, ids []id.LayerID, f []id.SceneID) (layer.GroupList, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "id", Value: bson.D{ {Key: "$in", Value: id.LayerIDToKeys(ids)}, }}, @@ -109,7 +109,7 @@ func (r *layerRepo) FindGroupBySceneAndLinkedDatasetSchema(ctx context.Context, } func (r *layerRepo) FindByProperty(ctx context.Context, id id.PropertyID, f []id.SceneID) (layer.Layer, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "$or", Value: []bson.D{ {{Key: "property", Value: id.String()}}, {{Key: "infobox.property", Value: id.String()}}, @@ -120,7 +120,7 @@ func (r *layerRepo) FindByProperty(ctx context.Context, id id.PropertyID, f []id } func (r *layerRepo) FindParentByID(ctx context.Context, id id.LayerID, f []id.SceneID) (*layer.Group, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "group.layers", Value: id.String()}, }, f) return r.findGroupOne(ctx, filter) @@ -170,7 +170,7 @@ func (r *layerRepo) RemoveByScene(ctx context.Context, sceneID id.SceneID) error func (r *layerRepo) FindByTag(ctx context.Context, tagID id.TagID, f []id.SceneID) (layer.List, error) { ids := []id.TagID{tagID} - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "tags", Value: bson.D{ {Key: "$in", Value: id.TagIDToKeys(ids)}, }}, @@ -179,7 +179,7 @@ func (r *layerRepo) FindByTag(ctx context.Context, tagID id.TagID, f []id.SceneI return r.find(ctx, nil, filter) } -func (r *layerRepo) find(ctx context.Context, dst layer.List, filter bson.D) (layer.List, error) { +func (r *layerRepo) find(ctx context.Context, dst layer.List, filter interface{}) (layer.List, error) { c := mongodoc.LayerConsumer{ Rows: dst, } @@ -189,7 +189,7 @@ func (r *layerRepo) find(ctx context.Context, dst layer.List, filter bson.D) (la return c.Rows, nil } -func (r *layerRepo) findOne(ctx context.Context, filter bson.D) (layer.Layer, error) { +func (r *layerRepo) findOne(ctx context.Context, filter interface{}) (layer.Layer, error) { c := mongodoc.LayerConsumer{} if err := r.client.FindOne(ctx, filter, &c); err != nil { return nil, err @@ -200,7 +200,7 @@ func (r *layerRepo) findOne(ctx context.Context, filter bson.D) (layer.Layer, er return *c.Rows[0], nil } -func (r *layerRepo) findItemOne(ctx context.Context, filter bson.D) (*layer.Item, error) { +func (r *layerRepo) findItemOne(ctx context.Context, filter interface{}) (*layer.Item, error) { c := mongodoc.LayerConsumer{} if err := r.client.FindOne(ctx, filter, &c); err != nil { return nil, err @@ -211,7 +211,7 @@ func (r *layerRepo) findItemOne(ctx context.Context, filter bson.D) (*layer.Item return c.ItemRows[0], nil } -func (r *layerRepo) findGroupOne(ctx context.Context, filter bson.D) (*layer.Group, error) { +func (r *layerRepo) findGroupOne(ctx context.Context, filter interface{}) (*layer.Group, error) { c := mongodoc.LayerConsumer{} if err := r.client.FindOne(ctx, filter, &c); err != nil { return nil, err @@ -231,7 +231,7 @@ func (r *layerRepo) findGroupOne(ctx context.Context, filter bson.D) (*layer.Gro // return c.Rows, pageInfo, nil // } -func (r *layerRepo) findItems(ctx context.Context, dst layer.ItemList, filter bson.D) (layer.ItemList, error) { +func (r *layerRepo) findItems(ctx context.Context, dst layer.ItemList, filter interface{}) (layer.ItemList, error) { c := mongodoc.LayerConsumer{ ItemRows: dst, } @@ -253,7 +253,7 @@ func (r *layerRepo) findItems(ctx context.Context, dst layer.ItemList, filter bs // return c.ItemRows, pageInfo, nil // } -func (r *layerRepo) findGroups(ctx context.Context, dst layer.GroupList, filter bson.D) (layer.GroupList, error) { +func (r *layerRepo) findGroups(ctx context.Context, dst layer.GroupList, filter interface{}) (layer.GroupList, error) { c := mongodoc.LayerConsumer{ GroupRows: dst, } @@ -266,7 +266,7 @@ func (r *layerRepo) findGroups(ctx context.Context, dst layer.GroupList, filter return c.GroupRows, nil } -// func (r *layerRepo) paginateGroups(ctx context.Context, filter bson.D, pagination *usecase.Pagination) (layer.GroupList, *usecase.PageInfo, error) { +// func (r *layerRepo) paginateGroups(ctx context.Context, filter interface{}, pagination *usecase.Pagination) (layer.GroupList, *usecase.PageInfo, error) { // var c mongodoc.LayerConsumer // pageInfo, err2 := r.client.Paginate(ctx, filter, pagination, &c) // if err2 != nil { @@ -323,7 +323,15 @@ func filterLayerGroups(ids []id.LayerID, rows []*layer.Group) []*layer.Group { return res } -func (*layerRepo) sceneFilter(filter bson.D, scenes []id.SceneID) bson.D { +func (*layerRepo) sceneFilter(filter bson.M, scenes []id.SceneID) bson.M { + if scenes == nil { + return filter + } + filter["scene"] = bson.M{"$in": id.SceneIDToKeys(scenes)} + return filter +} + +func (*layerRepo) sceneFilterD(filter bson.D, scenes []id.SceneID) bson.D { if scenes == nil { return filter } diff --git a/internal/infrastructure/mongo/property.go b/internal/infrastructure/mongo/property.go index 815c41d4..0ee95c85 100644 --- a/internal/infrastructure/mongo/property.go +++ b/internal/infrastructure/mongo/property.go @@ -23,7 +23,7 @@ func NewProperty(client *mongodoc.Client) repo.Property { } func (r *propertyRepo) init() { - i := r.client.CreateIndex(context.Background(), nil) + i := r.client.CreateIndex(context.Background(), []string{"scene"}) if len(i) > 0 { log.Infof("mongo: %s: index created: %s", "property", i) } diff --git a/internal/infrastructure/mongo/tag.go b/internal/infrastructure/mongo/tag.go index 58175649..2364795b 100644 --- a/internal/infrastructure/mongo/tag.go +++ b/internal/infrastructure/mongo/tag.go @@ -24,7 +24,7 @@ func NewTag(client *mongodoc.Client) repo.Tag { } func (r *tagRepo) init() { - i := r.client.CreateIndex(context.Background(), nil) + i := r.client.CreateIndex(context.Background(), []string{"scene"}) if len(i) > 0 { log.Infof("mongo: %s: index created: %s", "tag", i) } From ebea1cb6901b6b53dfa8426f6aad7e6087b578e8 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 12 Jan 2022 19:15:02 +0900 Subject: [PATCH 51/55] layer.IDList.RemoveLayer accepts multiple layers --- pkg/layer/id_list.go | 29 +++++++++-------------------- pkg/layer/id_list_test.go | 7 +++++++ 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/pkg/layer/id_list.go b/pkg/layer/id_list.go index ec7273cb..820e4eac 100644 --- a/pkg/layer/id_list.go +++ b/pkg/layer/id_list.go @@ -2,14 +2,12 @@ package layer import "github.com/reearth/reearth-backend/pkg/id" -// IDList _ type IDList struct { layers []id.LayerID // for checking duplication layerIDs map[id.LayerID]struct{} } -// NewIDList _ func NewIDList(layers []id.LayerID) *IDList { ll := IDList{} if len(layers) == 0 { @@ -24,7 +22,6 @@ func NewIDList(layers []id.LayerID) *IDList { return &ll } -// Layers _ func (l *IDList) Layers() []id.LayerID { if l == nil { return nil @@ -33,7 +30,6 @@ func (l *IDList) Layers() []id.LayerID { return result } -// HasLayer _ func (l *IDList) HasLayer(id id.LayerID) bool { if l == nil || len(l.layerIDs) == 0 { return false @@ -42,7 +38,6 @@ func (l *IDList) HasLayer(id id.LayerID) bool { return ok } -// LayerAt _ func (l *IDList) LayerAt(index int) id.LayerID { if l == nil || index < 0 || len(l.layers) <= index { return id.LayerID{} @@ -57,7 +52,6 @@ func (l *IDList) AtRef(index int) *id.LayerID { return &l.layers[index] } -// FindLayerIndex _ func (l *IDList) FindLayerIndex(id id.LayerID) int { if l == nil { return -1 @@ -70,7 +64,6 @@ func (l *IDList) FindLayerIndex(id id.LayerID) int { return -1 } -// LayerCount _ func (l *IDList) LayerCount() int { if l == nil { return 0 @@ -78,7 +71,6 @@ func (l *IDList) LayerCount() int { return len(l.layers) } -// AddLayer _ func (l *IDList) AddLayer(lid id.LayerID, index int) { if l == nil || l.HasLayer(lid) { return @@ -97,7 +89,6 @@ func (l *IDList) AddLayer(lid id.LayerID, index int) { } } -// AppendLayers _ func (l *IDList) AppendLayers(lid ...id.LayerID) *IDList { if l == nil { return NewIDList(lid) @@ -119,7 +110,6 @@ func (l *IDList) Clone() (l2 *IDList) { return NewIDList(l.layers) } -// AddOrMoveLayer _ func (l *IDList) AddOrMoveLayer(lid id.LayerID, index int) { if l == nil { return @@ -138,7 +128,6 @@ func (l *IDList) AddOrMoveLayer(lid id.LayerID, index int) { l.layerIDs[lid] = struct{}{} } -// MoveLayer _ func (l *IDList) MoveLayer(id id.LayerID, toIndex int) { if l == nil { return @@ -152,7 +141,6 @@ func (l *IDList) MoveLayer(id id.LayerID, toIndex int) { } } -// MoveLayerAt _ func (l *IDList) MoveLayerAt(fromIndex int, toIndex int) { if l == nil || len(l.layers) == 0 { return @@ -177,21 +165,23 @@ func (l *IDList) MoveLayerAt(fromIndex int, toIndex int) { l.layers = append(newSlice, l.layers[toIndex:]...) } -// RemoveLayer _ -func (l *IDList) RemoveLayer(id id.LayerID) { +func (l *IDList) RemoveLayer(ids ...id.LayerID) { if l == nil { return } - for index, layer := range l.layers { - if layer == id { - l.RemoveLayerAt(index) - return + for i := 0; i < len(l.layers); i++ { + layer := l.layers[i] + for _, id := range ids { + if layer == id { + l.RemoveLayerAt(i) + i-- + break + } } } } -// RemoveLayerAt _ func (l *IDList) RemoveLayerAt(index int) { if l == nil || len(l.layers) == 0 { return @@ -213,7 +203,6 @@ func (l *IDList) RemoveLayerAt(index int) { delete(l.layerIDs, layer) } -// Empty _ func (l *IDList) Empty() { if l == nil { return diff --git a/pkg/layer/id_list_test.go b/pkg/layer/id_list_test.go index 5edcf2bf..1c299318 100644 --- a/pkg/layer/id_list_test.go +++ b/pkg/layer/id_list_test.go @@ -130,4 +130,11 @@ func TestLayerIDList(t *testing.T) { assert.Equal(t, l3, layers.LayerAt(2)) assert.Equal(t, l4, layers.LayerAt(3)) assert.True(t, layers.HasLayer(l2)) + + // 1, 3 + + layers.RemoveLayer(l2, l4) + assert.Equal(t, 2, layers.LayerCount()) + assert.Equal(t, l1, layers.LayerAt(0)) + assert.Equal(t, l3, layers.LayerAt(1)) } From 121cd3f69b01e9e3ff1e91c2dfe9e2139eff8e77 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 12 Jan 2022 20:10:44 +0900 Subject: [PATCH 52/55] update schema in property on migration --- pkg/id/plugin.go | 10 ++++++++++ pkg/id/plugin_test.go | 13 +++++++++++++ pkg/id/property_schema.go | 8 ++++++++ pkg/id/property_schema_test.go | 16 ++++++++++++++++ pkg/property/diff.go | 2 ++ pkg/property/diff_test.go | 17 ++++++++++++----- pkg/property/property.go | 8 ++++++++ 7 files changed, 69 insertions(+), 5 deletions(-) diff --git a/pkg/id/plugin.go b/pkg/id/plugin.go index 6e3d5df8..85abaecb 100644 --- a/pkg/id/plugin.go +++ b/pkg/id/plugin.go @@ -105,6 +105,16 @@ func PluginIDFromRef(id *string) *PluginID { return &did } +// Clone duplicates the PluginID +func (d PluginID) Clone() PluginID { + return PluginID{ + name: d.name, + version: d.version, + sys: d.sys, + scene: d.scene.CopyRef(), + } +} + // IsNil checks if ID is empty or not. func (d PluginID) IsNil() bool { return d.name == "" && d.version == "" && d.scene == nil && d.sys == false diff --git a/pkg/id/plugin_test.go b/pkg/id/plugin_test.go index bdbf68fc..0c0318fa 100644 --- a/pkg/id/plugin_test.go +++ b/pkg/id/plugin_test.go @@ -330,6 +330,19 @@ func TestPluginIDFromRef(t *testing.T) { } } +func TestPluginID_Clone(t *testing.T) { + p := PluginID{ + name: "aaa", + version: "1.0.0", + sys: false, + scene: NewSceneID().Ref(), + } + c := p.Clone() + + assert.Equal(t, p, c) + assert.NotSame(t, p, c) +} + func TestPluginID_Name(t *testing.T) { plugin := MustPluginID("MyPlugin~1.0.0") diff --git a/pkg/id/property_schema.go b/pkg/id/property_schema.go index d9d81ceb..cf1d87fd 100644 --- a/pkg/id/property_schema.go +++ b/pkg/id/property_schema.go @@ -63,6 +63,14 @@ func PropertySchemaIDFromRef(id *string) *PropertySchemaID { return &did } +// Clone duplicates the PropertySchemaID +func (d PropertySchemaID) Clone() PropertySchemaID { + return PropertySchemaID{ + plugin: d.plugin.Clone(), + id: d.id, + } +} + // ID returns a fragment of just ID. func (d PropertySchemaID) ID() string { return d.id diff --git a/pkg/id/property_schema_test.go b/pkg/id/property_schema_test.go index 7adcb856..4913f6ef 100644 --- a/pkg/id/property_schema_test.go +++ b/pkg/id/property_schema_test.go @@ -215,6 +215,22 @@ func TestPropertySchemaIDFromRef(t *testing.T) { } } +func TestPropertySchemaID_Clone(t *testing.T) { + p := PropertySchemaID{ + id: "xxx", + plugin: PluginID{ + name: "aaa", + version: "1.0.0", + sys: false, + scene: NewSceneID().Ref(), + }, + } + c := p.Clone() + + assert.Equal(t, p, c) + assert.NotSame(t, p, c) +} + func TestPropertySchemaID_ID(t *testing.T) { propertySchemaID := MustPropertySchemaID("Test~2.0.0/test") assert.Equal(t, propertySchemaID.ID(), "test") diff --git a/pkg/property/diff.go b/pkg/property/diff.go index 23459a2a..62da32c9 100644 --- a/pkg/property/diff.go +++ b/pkg/property/diff.go @@ -64,6 +64,8 @@ func (d *SchemaDiff) Migrate(p *Property) (res bool) { return } + res = p.updateSchema(d.To) + for _, dd := range d.Deleted { if p.RemoveFields(SchemaFieldPointer(dd).Pointer()) { res = true diff --git a/pkg/property/diff_test.go b/pkg/property/diff_test.go index 02605b8d..be462430 100644 --- a/pkg/property/diff_test.go +++ b/pkg/property/diff_test.go @@ -235,6 +235,7 @@ func TestSchemaDiffFromProperty(t *testing.T) { func TestSchemaDiff_Migrate(t *testing.T) { itemID := NewItemID() NewItemID = func() ItemID { return itemID } + newSchemaID := MustSchemaID("x~1.0.0/ax") tests := []struct { name string @@ -246,6 +247,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { { name: "deleted and type changed", target: &SchemaDiff{ + To: newSchemaID, Deleted: []SchemaDiffDeleted{ {SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, }, @@ -258,7 +260,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { wantProperty: &Property{ id: testProperty1.ID(), scene: testProperty1.Scene(), - schema: testProperty1.Schema(), + schema: newSchemaID, items: []Item{ &Group{ itemBase: itemBase{ @@ -292,6 +294,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { { name: "moved", target: &SchemaDiff{ + To: newSchemaID, Moved: []SchemaDiffMoved{ { From: SchemaFieldPointer{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, @@ -304,7 +307,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { wantProperty: &Property{ id: testProperty1.ID(), scene: testProperty1.Scene(), - schema: testProperty1.Schema(), + schema: newSchemaID, items: []Item{ &Group{ itemBase: itemBase{ @@ -329,6 +332,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { { name: "moved and type changed", target: &SchemaDiff{ + To: newSchemaID, Moved: []SchemaDiffMoved{ { From: SchemaFieldPointer{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, @@ -344,7 +348,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { wantProperty: &Property{ id: testProperty1.ID(), scene: testProperty1.Scene(), - schema: testProperty1.Schema(), + schema: newSchemaID, items: []Item{ &Group{ itemBase: itemBase{ @@ -371,6 +375,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { { name: "group -> list", target: &SchemaDiff{ + To: newSchemaID, Moved: []SchemaDiffMoved{ { From: SchemaFieldPointer{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}, @@ -383,7 +388,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { wantProperty: &Property{ id: testProperty1.ID(), scene: testProperty1.Scene(), - schema: testProperty1.Schema(), + schema: newSchemaID, items: []Item{ &Group{ itemBase: itemBase{ @@ -401,6 +406,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { { name: "list -> group", target: &SchemaDiff{ + To: newSchemaID, Moved: []SchemaDiffMoved{ { From: SchemaFieldPointer{SchemaGroup: testGroup2.SchemaGroup(), Field: testField2.Field()}, @@ -413,7 +419,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { wantProperty: &Property{ id: testProperty1.ID(), scene: testProperty1.Scene(), - schema: testProperty1.Schema(), + schema: newSchemaID, items: []Item{ testGroup1, &GroupList{ @@ -446,6 +452,7 @@ func TestSchemaDiff_Migrate(t *testing.T) { { name: "nil property", target: &SchemaDiff{ + To: newSchemaID, Deleted: []SchemaDiffDeleted{{SchemaGroup: testGroup1.SchemaGroup(), Field: testField1.Field()}}, }, args: nil, diff --git a/pkg/property/property.go b/pkg/property/property.go index 9ad5825d..d2f3f777 100644 --- a/pkg/property/property.go +++ b/pkg/property/property.go @@ -607,3 +607,11 @@ func (p *Property) GuessSchema() *Schema { } return nil } + +func (p *Property) updateSchema(s SchemaID) bool { + if p == nil || s.IsNil() || p.schema.Equal(s) { + return false + } + p.schema = s.Clone() + return true +} From 05de89945d0248688797a48413c8dc22f0b90347 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 12 Jan 2022 20:34:16 +0900 Subject: [PATCH 53/55] rename and refactor scene.PluginSystem --- .../adapter/gql/gqlmodel/convert_scene.go | 2 +- .../adapter/gql/resolver_mutation_scene.go | 4 +- .../infrastructure/mongo/mongodoc/scene.go | 4 +- internal/usecase/interactor/scene.go | 10 +- pkg/scene/builder.go | 19 ++-- pkg/scene/builder/builder_test.go | 2 +- pkg/scene/builder/scene.go | 2 +- pkg/scene/builder_test.go | 30 +++--- pkg/scene/plugin.go | 38 ++++--- pkg/scene/{plugin_system.go => plugins.go} | 54 ++++++---- ...{plugin_system_test.go => plugins_test.go} | 99 ++++++++++--------- pkg/scene/scene.go | 8 +- pkg/scene/scene_test.go | 2 +- pkg/scene/sceneops/plugin_migrator.go | 6 +- 14 files changed, 152 insertions(+), 128 deletions(-) rename pkg/scene/{plugin_system.go => plugins.go} (60%) rename pkg/scene/{plugin_system_test.go => plugins_test.go} (70%) diff --git a/internal/adapter/gql/gqlmodel/convert_scene.go b/internal/adapter/gql/gqlmodel/convert_scene.go index 5fae166a..76862dee 100644 --- a/internal/adapter/gql/gqlmodel/convert_scene.go +++ b/internal/adapter/gql/gqlmodel/convert_scene.go @@ -55,7 +55,7 @@ func ToScene(scene *scene.Scene) *Scene { clusters = append(clusters, ToCluster(c)) } - scenePlugins := scene.PluginSystem().Plugins() + scenePlugins := scene.Plugins().Plugins() plugins := make([]*ScenePlugin, 0, len(scenePlugins)) for _, sp := range scenePlugins { plugins = append(plugins, ToScenePlugin(sp)) diff --git a/internal/adapter/gql/resolver_mutation_scene.go b/internal/adapter/gql/resolver_mutation_scene.go index 306fcb2b..d4c63d4b 100644 --- a/internal/adapter/gql/resolver_mutation_scene.go +++ b/internal/adapter/gql/resolver_mutation_scene.go @@ -153,7 +153,7 @@ func (r *mutationResolver) UploadPlugin(ctx context.Context, input gqlmodel.Uplo return &gqlmodel.UploadPluginPayload{ Plugin: gqlmodel.ToPlugin(p), Scene: gqlmodel.ToScene(s), - ScenePlugin: gqlmodel.ToScenePlugin(s.PluginSystem().Plugin(p.ID())), + ScenePlugin: gqlmodel.ToScenePlugin(s.Plugins().Plugin(p.ID())), }, nil } @@ -192,7 +192,7 @@ func (r *mutationResolver) UpgradePlugin(ctx context.Context, input gqlmodel.Upg return &gqlmodel.UpgradePluginPayload{ Scene: gqlmodel.ToScene(s), - ScenePlugin: gqlmodel.ToScenePlugin(s.PluginSystem().Plugin(input.ToPluginID)), + ScenePlugin: gqlmodel.ToScenePlugin(s.Plugins().Plugin(input.ToPluginID)), }, nil } diff --git a/internal/infrastructure/mongo/mongodoc/scene.go b/internal/infrastructure/mongo/mongodoc/scene.go index fbb19a2b..f18f4cb8 100644 --- a/internal/infrastructure/mongo/mongodoc/scene.go +++ b/internal/infrastructure/mongo/mongodoc/scene.go @@ -91,7 +91,7 @@ func (c *SceneIDConsumer) Consume(raw bson.Raw) error { func NewScene(scene *scene.Scene) (*SceneDocument, string) { widgets := scene.WidgetSystem().Widgets() - plugins := scene.PluginSystem().Plugins() + plugins := scene.Plugins().Plugins() clusters := scene.Clusters().Clusters() widgetsDoc := make([]SceneWidgetDocument, 0, len(widgets)) @@ -225,7 +225,7 @@ func (d *SceneDocument) Model() (*scene.Scene, error) { Clusters(cl). WidgetSystem(scene.NewWidgetSystem(ws)). WidgetAlignSystem(d.AlignSystem.Model()). - PluginSystem(scene.NewPluginSystem(ps)). + Plugins(scene.NewPlugins(ps)). UpdatedAt(d.UpdateAt). Property(prid). Build() diff --git a/internal/usecase/interactor/scene.go b/internal/usecase/interactor/scene.go index 44a548eb..369b4115 100644 --- a/internal/usecase/interactor/scene.go +++ b/internal/usecase/interactor/scene.go @@ -99,7 +99,7 @@ func (i *Scene) Create(ctx context.Context, pid id.ProjectID, operator *usecase. return nil, err } - ps := scene.NewPluginSystem([]*scene.Plugin{ + ps := scene.NewPlugins([]*scene.Plugin{ scene.NewPlugin(id.OfficialPluginID, nil), }) @@ -119,7 +119,7 @@ func (i *Scene) Create(ctx context.Context, pid id.ProjectID, operator *usecase. Team(prj.Team()). Property(p.ID()). RootLayer(rootLayer.ID()). - PluginSystem(ps). + Plugins(ps). Build() if err != nil { @@ -458,7 +458,7 @@ func (i *Scene) InstallPlugin(ctx context.Context, sid id.SceneID, pid id.Plugin return nil, pid, nil, err2 } - if s.PluginSystem().HasPlugin(pid) { + if s.Plugins().HasNamed(pid.Name()) { return nil, pid, nil, interfaces.ErrPluginAlreadyInstalled } @@ -486,7 +486,7 @@ func (i *Scene) InstallPlugin(ctx context.Context, sid id.SceneID, pid id.Plugin propertyID = &prid } - s.PluginSystem().Add(scene.NewPlugin(pid, propertyID)) + s.Plugins().Add(scene.NewPlugin(pid, propertyID)) if p != nil { if err := i.propertyRepo.Save(ctx, p); err != nil { @@ -539,7 +539,7 @@ func (i *Scene) UninstallPlugin(ctx context.Context, sid id.SceneID, pid id.Plug return nil, err } - ps := scene.PluginSystem() + ps := scene.Plugins() if !ps.Has(pid) { return nil, interfaces.ErrPluginNotInstalled } diff --git a/pkg/scene/builder.go b/pkg/scene/builder.go index 7b15de0e..93dad935 100644 --- a/pkg/scene/builder.go +++ b/pkg/scene/builder.go @@ -14,7 +14,6 @@ func New() *Builder { return &Builder{scene: &Scene{}} } -// Build _ func (b *Builder) Build() (*Scene, error) { if b.scene.id.ID().IsNil() { return nil, id.ErrInvalidID @@ -31,8 +30,8 @@ func (b *Builder) Build() (*Scene, error) { if b.scene.widgetAlignSystem == nil { b.scene.widgetAlignSystem = NewWidgetAlignSystem() } - if b.scene.pluginSystem == nil { - b.scene.pluginSystem = NewPluginSystem(nil) + if b.scene.plugins == nil { + b.scene.plugins = NewPlugins(nil) } if b.scene.updatedAt.IsZero() { b.scene.updatedAt = b.scene.CreatedAt() @@ -73,14 +72,13 @@ func (b *Builder) UpdatedAt(updatedAt time.Time) *Builder { return b } -func (b *Builder) WidgetSystem(widgetSystem *WidgetSystem) *Builder { - widgetSystem2 := *widgetSystem - b.scene.widgetSystem = &widgetSystem2 +func (b *Builder) WidgetSystem(w *WidgetSystem) *Builder { + b.scene.widgetSystem = w return b } -func (b *Builder) WidgetAlignSystem(widgetAlignSystem *WidgetAlignSystem) *Builder { - b.scene.widgetAlignSystem = widgetAlignSystem +func (b *Builder) WidgetAlignSystem(w *WidgetAlignSystem) *Builder { + b.scene.widgetAlignSystem = w return b } @@ -89,9 +87,8 @@ func (b *Builder) RootLayer(rootLayer id.LayerID) *Builder { return b } -func (b *Builder) PluginSystem(pluginSystem *PluginSystem) *Builder { - pluginSystem2 := *pluginSystem - b.scene.pluginSystem = &pluginSystem2 +func (b *Builder) Plugins(p *Plugins) *Builder { + b.scene.plugins = p return b } diff --git a/pkg/scene/builder/builder_test.go b/pkg/scene/builder/builder_test.go index 42b8cc49..d801b235 100644 --- a/pkg/scene/builder/builder_test.go +++ b/pkg/scene/builder/builder_test.go @@ -396,7 +396,7 @@ func TestSceneBuilder(t *testing.T) { WidgetSystem(scene.NewWidgetSystem([]*scene.Widget{ sceneWidget1, sceneWidget2, })). - PluginSystem(scene.NewPluginSystem([]*scene.Plugin{scenePlugin1})). + Plugins(scene.NewPlugins([]*scene.Plugin{scenePlugin1})). RootLayer(rootLayer.ID()). MustBuild() diff --git a/pkg/scene/builder/scene.go b/pkg/scene/builder/scene.go index 5060f5d9..7a42b28f 100644 --- a/pkg/scene/builder/scene.go +++ b/pkg/scene/builder/scene.go @@ -42,7 +42,7 @@ func (b *Builder) scene(ctx context.Context, s *scene.Scene, publishedAt time.Ti } func (b *Builder) plugins(ctx context.Context, s *scene.Scene, p []*property.Property) map[string]propertyJSON { - scenePlugins := s.PluginSystem().Plugins() + scenePlugins := s.Plugins().Plugins() res := map[string]propertyJSON{} for _, sp := range scenePlugins { if sp == nil { diff --git a/pkg/scene/builder_test.go b/pkg/scene/builder_test.go index 8dadac45..09211b82 100644 --- a/pkg/scene/builder_test.go +++ b/pkg/scene/builder_test.go @@ -34,11 +34,11 @@ func TestBuilder_Property(t *testing.T) { } func TestBuilder_PluginSystem(t *testing.T) { - ps := NewPluginSystem([]*Plugin{ + ps := NewPlugins([]*Plugin{ NewPlugin(id.OfficialPluginID, id.NewPropertyID().Ref()), }) - b := New().NewID().RootLayer(id.NewLayerID()).Team(id.NewTeamID()).PluginSystem(ps).MustBuild() - assert.Equal(t, ps, b.PluginSystem()) + b := New().NewID().RootLayer(id.NewLayerID()).Team(id.NewTeamID()).Plugins(ps).MustBuild() + assert.Equal(t, ps, b.Plugins()) } func TestBuilder_Project(t *testing.T) { @@ -72,7 +72,7 @@ func TestBuilder_Build(t *testing.T) { MustNewWidget(id.WidgetID(nid), id.OfficialPluginID, "xxx", ppid, true, false), }) was := NewWidgetAlignSystem() - ps := NewPluginSystem([]*Plugin{ + ps := NewPlugins([]*Plugin{ NewPlugin(id.OfficialPluginID, ppid.Ref()), }) testCases := []struct { @@ -83,7 +83,7 @@ func TestBuilder_Build(t *testing.T) { RootLayer id.LayerID WidgetSystem *WidgetSystem WidgetAlignSystem *WidgetAlignSystem - PluginSystem *PluginSystem + PluginSystem *Plugins UpdatedAt time.Time Property id.PropertyID Expected struct { @@ -93,7 +93,7 @@ func TestBuilder_Build(t *testing.T) { RootLayer id.LayerID WidgetSystem *WidgetSystem WidgetAlignSystem *WidgetAlignSystem - PluginSystem *PluginSystem + PluginSystem *Plugins UpdatedAt time.Time Property id.PropertyID } @@ -156,7 +156,7 @@ func TestBuilder_Build(t *testing.T) { RootLayer id.LayerID WidgetSystem *WidgetSystem WidgetAlignSystem *WidgetAlignSystem - PluginSystem *PluginSystem + PluginSystem *Plugins UpdatedAt time.Time Property id.PropertyID }{ @@ -182,7 +182,7 @@ func TestBuilder_Build(t *testing.T) { WidgetSystem(tc.WidgetSystem). WidgetAlignSystem(tc.WidgetAlignSystem). Project(tc.Project). - PluginSystem(tc.PluginSystem). + Plugins(tc.PluginSystem). Property(tc.Property). RootLayer(tc.RootLayer). Team(tc.Team). @@ -194,7 +194,7 @@ func TestBuilder_Build(t *testing.T) { assert.Equal(tt, tc.Expected.Team, res.Team()) assert.Equal(tt, tc.Expected.RootLayer, res.RootLayer()) assert.Equal(tt, tc.Expected.Property, res.Property()) - assert.Equal(tt, tc.Expected.PluginSystem, res.PluginSystem()) + assert.Equal(tt, tc.Expected.PluginSystem, res.Plugins()) assert.Equal(tt, tc.Expected.WidgetSystem, res.WidgetSystem()) assert.Equal(tt, tc.Expected.Project, res.Project()) } else { @@ -215,7 +215,7 @@ func TestBuilder_MustBuild(t *testing.T) { MustNewWidget(id.WidgetID(nid), id.OfficialPluginID, "xxx", ppid, true, false), }) was := NewWidgetAlignSystem() - ps := NewPluginSystem([]*Plugin{ + ps := NewPlugins([]*Plugin{ NewPlugin(id.OfficialPluginID, ppid.Ref()), }) testCases := []struct { @@ -226,7 +226,7 @@ func TestBuilder_MustBuild(t *testing.T) { RootLayer id.LayerID WidgetSystem *WidgetSystem WidgetAlignSystem *WidgetAlignSystem - PluginSystem *PluginSystem + PluginSystem *Plugins UpdatedAt time.Time Property id.PropertyID Expected struct { @@ -236,7 +236,7 @@ func TestBuilder_MustBuild(t *testing.T) { RootLayer id.LayerID WidgetSystem *WidgetSystem WidgetAlignSystem *WidgetAlignSystem - PluginSystem *PluginSystem + PluginSystem *Plugins UpdatedAt time.Time Property id.PropertyID } @@ -299,7 +299,7 @@ func TestBuilder_MustBuild(t *testing.T) { RootLayer id.LayerID WidgetSystem *WidgetSystem WidgetAlignSystem *WidgetAlignSystem - PluginSystem *PluginSystem + PluginSystem *Plugins UpdatedAt time.Time Property id.PropertyID }{ @@ -328,7 +328,7 @@ func TestBuilder_MustBuild(t *testing.T) { assert.Equal(tt, tc.Expected.Team, res.Team()) assert.Equal(tt, tc.Expected.RootLayer, res.RootLayer()) assert.Equal(tt, tc.Expected.Property, res.Property()) - assert.Equal(tt, tc.Expected.PluginSystem, res.PluginSystem()) + assert.Equal(tt, tc.Expected.PluginSystem, res.Plugins()) assert.Equal(tt, tc.Expected.WidgetSystem, res.WidgetSystem()) assert.Equal(tt, tc.Expected.WidgetAlignSystem, res.WidgetAlignSystem()) assert.Equal(tt, tc.Expected.Project, res.Project()) @@ -340,7 +340,7 @@ func TestBuilder_MustBuild(t *testing.T) { WidgetSystem(tc.WidgetSystem). WidgetAlignSystem(tc.WidgetAlignSystem). Project(tc.Project). - PluginSystem(tc.PluginSystem). + Plugins(tc.PluginSystem). Property(tc.Property). RootLayer(tc.RootLayer). Team(tc.Team). diff --git a/pkg/scene/plugin.go b/pkg/scene/plugin.go index c15ef56e..8bdbe39a 100644 --- a/pkg/scene/plugin.go +++ b/pkg/scene/plugin.go @@ -10,25 +10,39 @@ type Plugin struct { } func NewPlugin(plugin id.PluginID, property *id.PropertyID) *Plugin { - if property != nil { - property2 := *property - property = &property2 - } return &Plugin{ plugin: plugin, - property: property, + property: property.CopyRef(), } } -func (s Plugin) Plugin() id.PluginID { +func (s *Plugin) Plugin() id.PluginID { + if s == nil { + return id.PluginID{} + } return s.plugin } -func (s Plugin) Property() *id.PropertyID { - property := s.property - if property != nil { - property2 := *property - property = &property2 +func (s *Plugin) PluginRef() *id.PluginID { + if s == nil { + return nil + } + return s.plugin.Ref() +} + +func (s *Plugin) Property() *id.PropertyID { + if s == nil { + return nil + } + return s.property.CopyRef() +} + +func (s *Plugin) Clone() *Plugin { + if s == nil { + return nil + } + return &Plugin{ + plugin: s.plugin, + property: s.property.CopyRef(), } - return property } diff --git a/pkg/scene/plugin_system.go b/pkg/scene/plugins.go similarity index 60% rename from pkg/scene/plugin_system.go rename to pkg/scene/plugins.go index a10a6aa9..18efeea3 100644 --- a/pkg/scene/plugin_system.go +++ b/pkg/scene/plugins.go @@ -4,14 +4,15 @@ import ( "github.com/reearth/reearth-backend/pkg/id" ) -type PluginSystem struct { +type Plugins struct { plugins []*Plugin } -func NewPluginSystem(p []*Plugin) *PluginSystem { - if p == nil { - return &PluginSystem{plugins: []*Plugin{}} +func NewPlugins(p []*Plugin) *Plugins { + if len(p) == 0 { + return &Plugins{} } + p2 := make([]*Plugin, 0, len(p)) for _, p1 := range p { if p1 == nil { @@ -29,14 +30,15 @@ func NewPluginSystem(p []*Plugin) *PluginSystem { p2 = append(p2, &p3) } } - return &PluginSystem{plugins: p2} + + return &Plugins{plugins: p2} } -func (p *PluginSystem) Plugins() []*Plugin { +func (p *Plugins) Plugins() []*Plugin { return append([]*Plugin{}, p.plugins...) } -func (p *PluginSystem) Property(id id.PluginID) *id.PropertyID { +func (p *Plugins) Property(id id.PluginID) *id.PropertyID { for _, p := range p.plugins { if p.plugin.Equal(id) { return p.property.CopyRef() @@ -45,7 +47,7 @@ func (p *PluginSystem) Property(id id.PluginID) *id.PropertyID { return nil } -func (p *PluginSystem) Has(id id.PluginID) bool { +func (p *Plugins) Has(id id.PluginID) bool { for _, p2 := range p.plugins { if p2.plugin.Equal(id) { return true @@ -54,8 +56,7 @@ func (p *PluginSystem) Has(id id.PluginID) bool { return false } -func (p *PluginSystem) HasPlugin(id id.PluginID) bool { - name := id.Name() +func (p *Plugins) HasNamed(name string) bool { for _, p2 := range p.plugins { if p2.plugin.Name() == name { return true @@ -64,15 +65,14 @@ func (p *PluginSystem) HasPlugin(id id.PluginID) bool { return false } -func (p *PluginSystem) Add(sp *Plugin) { - if sp == nil || p.Has(sp.plugin) || sp.plugin.Equal(id.OfficialPluginID) { +func (p *Plugins) Add(sp *Plugin) { + if sp == nil || p.HasNamed(sp.plugin.Name()) || sp.plugin.Equal(id.OfficialPluginID) { return } - sp2 := *sp - p.plugins = append(p.plugins, &sp2) + p.plugins = append(p.plugins, sp) } -func (p *PluginSystem) Remove(pid id.PluginID) { +func (p *Plugins) Remove(pid id.PluginID) { if pid.Equal(id.OfficialPluginID) { return } @@ -84,7 +84,11 @@ func (p *PluginSystem) Remove(pid id.PluginID) { } } -func (p *PluginSystem) Upgrade(pid, newpid id.PluginID, pr *id.PropertyID, deleteProperty bool) { +func (p *Plugins) Upgrade(pid, newpid id.PluginID, pr *id.PropertyID, deleteProperty bool) { + if p == nil || p.HasNamed(newpid.Name()) { + return + } + for i, pp := range p.plugins { if pp.plugin.Equal(id.OfficialPluginID) { continue @@ -100,14 +104,13 @@ func (p *PluginSystem) Upgrade(pid, newpid id.PluginID, pr *id.PropertyID, delet if deleteProperty { newp = nil } - p.plugins[i] = &Plugin{plugin: newpid, property: newp} + p.plugins[i] = NewPlugin(newpid, newp) return } } } -// Properties _ -func (p *PluginSystem) Properties() []id.PropertyID { +func (p *Plugins) Properties() []id.PropertyID { if p == nil { return nil } @@ -120,9 +123,18 @@ func (p *PluginSystem) Properties() []id.PropertyID { return res } -func (p *PluginSystem) Plugin(pluginID id.PluginID) *Plugin { +func (p *Plugins) Plugin(i id.PluginID) *Plugin { + for _, pp := range p.plugins { + if pp.plugin == i { + return pp + } + } + return nil +} + +func (p *Plugins) PluginByName(n string) *Plugin { for _, pp := range p.plugins { - if pp.plugin == pluginID { + if pp.plugin.Name() == n { return pp } } diff --git a/pkg/scene/plugin_system_test.go b/pkg/scene/plugins_test.go similarity index 70% rename from pkg/scene/plugin_system_test.go rename to pkg/scene/plugins_test.go index d5dcd8bb..9e231893 100644 --- a/pkg/scene/plugin_system_test.go +++ b/pkg/scene/plugins_test.go @@ -13,17 +13,17 @@ func TestNewPluginSystem(t *testing.T) { testCases := []struct { Name string Input []*Plugin - Expected *PluginSystem + Expected *Plugins }{ { Name: "nil plugin list", Input: nil, - Expected: &PluginSystem{plugins: []*Plugin{}}, + Expected: &Plugins{}, }, { Name: "plugin list with nil", Input: []*Plugin{nil}, - Expected: &PluginSystem{plugins: []*Plugin{}}, + Expected: &Plugins{plugins: []*Plugin{}}, }, { Name: "plugin list with matched values", @@ -33,7 +33,7 @@ func TestNewPluginSystem(t *testing.T) { property: pr, }, }, - Expected: &PluginSystem{plugins: []*Plugin{ + Expected: &Plugins{plugins: []*Plugin{ NewPlugin(pid, pr), }}, }, @@ -49,7 +49,7 @@ func TestNewPluginSystem(t *testing.T) { property: pr, }, }, - Expected: &PluginSystem{plugins: []*Plugin{ + Expected: &Plugins{plugins: []*Plugin{ NewPlugin(pid, pr), }}, }, @@ -58,7 +58,7 @@ func TestNewPluginSystem(t *testing.T) { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() - res := NewPluginSystem(tc.Input) + res := NewPlugins(tc.Input) assert.Equal(tt, tc.Expected, res) }) } @@ -70,25 +70,25 @@ func TestPluginSystem_Property(t *testing.T) { testCases := []struct { Name string Input id.PluginID - PS *PluginSystem + PS *Plugins Expected *id.PropertyID }{ { Name: "property is found", Input: pid, - PS: NewPluginSystem([]*Plugin{NewPlugin(pid, pr)}), + PS: NewPlugins([]*Plugin{NewPlugin(pid, pr)}), Expected: pr, }, { Name: "property is nil", Input: pid, - PS: NewPluginSystem([]*Plugin{NewPlugin(pid, nil)}), + PS: NewPlugins([]*Plugin{NewPlugin(pid, nil)}), Expected: nil, }, { Name: "property is not found", Input: pid, - PS: NewPluginSystem([]*Plugin{NewPlugin(id.MustPluginID("zzz~1.1.1"), pr)}), + PS: NewPlugins([]*Plugin{NewPlugin(id.MustPluginID("zzz~1.1.1"), pr)}), Expected: nil, }, } @@ -108,19 +108,19 @@ func TestPluginSystem_Plugin(t *testing.T) { testCases := []struct { Name string Input id.PluginID - PS *PluginSystem + PS *Plugins Expected *Plugin }{ { Name: "plugin is found", Input: pid, - PS: NewPluginSystem([]*Plugin{NewPlugin(pid, pr)}), + PS: NewPlugins([]*Plugin{NewPlugin(pid, pr)}), Expected: NewPlugin(pid, pr), }, { Name: "plugin is not found", Input: pid, - PS: NewPluginSystem([]*Plugin{NewPlugin(id.MustPluginID("zzz~1.1.1"), pr)}), + PS: NewPlugins([]*Plugin{NewPlugin(id.MustPluginID("zzz~1.1.1"), pr)}), Expected: nil, }, } @@ -139,7 +139,7 @@ func TestPluginSystem_Properties(t *testing.T) { pr2 := id.NewPropertyID().Ref() testCases := []struct { Name string - PS *PluginSystem + PS *Plugins Expected []id.PropertyID }{ { @@ -149,7 +149,7 @@ func TestPluginSystem_Properties(t *testing.T) { }, { Name: "get properties", - PS: NewPluginSystem([]*Plugin{ + PS: NewPlugins([]*Plugin{ NewPlugin(id.MustPluginID("zzz~1.1.1"), pr), NewPlugin(id.MustPluginID("xxx~1.1.1"), pr2), }), @@ -172,19 +172,19 @@ func TestPluginSystem_Has(t *testing.T) { testCases := []struct { Name string Input id.PluginID - PS *PluginSystem + PS *Plugins Expected bool }{ { Name: "property is found", Input: pid, - PS: NewPluginSystem([]*Plugin{NewPlugin(pid, pr)}), + PS: NewPlugins([]*Plugin{NewPlugin(pid, pr)}), Expected: true, }, { Name: "property is not found", Input: pid, - PS: NewPluginSystem([]*Plugin{NewPlugin(id.MustPluginID("zzz~1.1.1"), pr)}), + PS: NewPlugins([]*Plugin{NewPlugin(id.MustPluginID("zzz~1.1.1"), pr)}), Expected: false, }, } @@ -203,28 +203,29 @@ func TestPluginSystem_HasPlugin(t *testing.T) { pr := id.NewPropertyID().Ref() testCases := []struct { Name string - Input id.PluginID - PS *PluginSystem + Input string + PS *Plugins Expected bool }{ { Name: "property is found", - Input: pid, - PS: NewPluginSystem([]*Plugin{NewPlugin(pid, pr)}), + Input: "xxx", + PS: NewPlugins([]*Plugin{NewPlugin(pid, pr)}), Expected: true, }, { Name: "property is not found", - Input: pid, - PS: NewPluginSystem([]*Plugin{NewPlugin(id.MustPluginID("zzz~1.1.1"), pr)}), + Input: "xxx", + PS: NewPlugins([]*Plugin{NewPlugin(id.MustPluginID("zzz~1.1.1"), pr)}), Expected: false, }, } + for _, tc := range testCases { tc := tc t.Run(tc.Name, func(tt *testing.T) { tt.Parallel() - res := tc.PS.HasPlugin(tc.Input) + res := tc.PS.HasNamed(tc.Input) assert.Equal(tt, tc.Expected, res) }) } @@ -236,31 +237,31 @@ func TestPluginSystem_Add(t *testing.T) { testCases := []struct { Name string Input *Plugin - PS, Expected *PluginSystem + PS, Expected *Plugins }{ { Name: "add nil plugin", Input: nil, - PS: NewPluginSystem([]*Plugin{NewPlugin(pid, pr)}), - Expected: NewPluginSystem([]*Plugin{NewPlugin(pid, pr)}), + PS: NewPlugins([]*Plugin{NewPlugin(pid, pr)}), + Expected: NewPlugins([]*Plugin{NewPlugin(pid, pr)}), }, { Name: "add existing plugin", Input: NewPlugin(pid, pr), - PS: NewPluginSystem([]*Plugin{NewPlugin(pid, pr)}), - Expected: NewPluginSystem([]*Plugin{NewPlugin(pid, pr)}), + PS: NewPlugins([]*Plugin{NewPlugin(pid, pr)}), + Expected: NewPlugins([]*Plugin{NewPlugin(pid, pr)}), }, { Name: "add official plugin", Input: NewPlugin(id.OfficialPluginID, pr), - PS: NewPluginSystem([]*Plugin{NewPlugin(pid, pr)}), - Expected: NewPluginSystem([]*Plugin{NewPlugin(pid, pr)}), + PS: NewPlugins([]*Plugin{NewPlugin(pid, pr)}), + Expected: NewPlugins([]*Plugin{NewPlugin(pid, pr)}), }, { Name: "add new plugin", Input: NewPlugin(pid, pr), - PS: NewPluginSystem([]*Plugin{}), - Expected: NewPluginSystem([]*Plugin{NewPlugin(pid, pr)}), + PS: NewPlugins([]*Plugin{}), + Expected: NewPlugins([]*Plugin{NewPlugin(pid, pr)}), }, } for _, tc := range testCases { @@ -279,19 +280,19 @@ func TestPluginSystem_Remove(t *testing.T) { testCases := []struct { Name string Input id.PluginID - PS, Expected *PluginSystem + PS, Expected *Plugins }{ { Name: "remove official plugin", Input: id.OfficialPluginID, - PS: NewPluginSystem([]*Plugin{NewPlugin(id.OfficialPluginID, pr)}), - Expected: NewPluginSystem([]*Plugin{NewPlugin(id.OfficialPluginID, pr)}), + PS: NewPlugins([]*Plugin{NewPlugin(id.OfficialPluginID, pr)}), + Expected: NewPlugins([]*Plugin{NewPlugin(id.OfficialPluginID, pr)}), }, { Name: "remove a plugin", Input: pid, - PS: NewPluginSystem([]*Plugin{NewPlugin(pid, pr)}), - Expected: NewPluginSystem([]*Plugin{}), + PS: NewPlugins([]*Plugin{NewPlugin(pid, pr)}), + Expected: &Plugins{plugins: []*Plugin{}}, }, } for _, tc := range testCases { @@ -319,16 +320,16 @@ func TestPluginSystem_Upgrade(t *testing.T) { tests := []struct { name string args args - target *PluginSystem - want *PluginSystem + target *Plugins + want *Plugins }{ { name: "upgrade official plugin", args: args{ pid: id.OfficialPluginID, }, - target: NewPluginSystem([]*Plugin{NewPlugin(id.OfficialPluginID, pr1)}), - want: NewPluginSystem([]*Plugin{NewPlugin(id.OfficialPluginID, pr1)}), + target: NewPlugins([]*Plugin{NewPlugin(id.OfficialPluginID, pr1)}), + want: NewPlugins([]*Plugin{NewPlugin(id.OfficialPluginID, pr1)}), }, { name: "upgrade a plugin", @@ -336,8 +337,8 @@ func TestPluginSystem_Upgrade(t *testing.T) { pid: pid, newpid: nid, }, - target: NewPluginSystem([]*Plugin{NewPlugin(pid, pr1)}), - want: NewPluginSystem([]*Plugin{NewPlugin(nid, pr1)}), + target: NewPlugins([]*Plugin{NewPlugin(pid, pr1)}), + want: NewPlugins([]*Plugin{NewPlugin(nid, pr1)}), }, { name: "upgrade a property", @@ -345,8 +346,8 @@ func TestPluginSystem_Upgrade(t *testing.T) { pid: pid, pr: pr2, }, - target: NewPluginSystem([]*Plugin{NewPlugin(pid, pr1)}), - want: NewPluginSystem([]*Plugin{NewPlugin(pid, pr2)}), + target: NewPlugins([]*Plugin{NewPlugin(pid, pr1)}), + want: NewPlugins([]*Plugin{NewPlugin(pid, pr2)}), }, { name: "delete a property", @@ -354,8 +355,8 @@ func TestPluginSystem_Upgrade(t *testing.T) { pid: pid, deleteProperty: true, }, - target: NewPluginSystem([]*Plugin{NewPlugin(pid, pr1)}), - want: NewPluginSystem([]*Plugin{NewPlugin(pid, nil)}), + target: NewPlugins([]*Plugin{NewPlugin(pid, pr1)}), + want: NewPlugins([]*Plugin{NewPlugin(pid, nil)}), }, } for _, tt := range tests { diff --git a/pkg/scene/scene.go b/pkg/scene/scene.go index 182790d9..d97b2b1d 100644 --- a/pkg/scene/scene.go +++ b/pkg/scene/scene.go @@ -16,7 +16,7 @@ type Scene struct { rootLayer id.LayerID widgetSystem *WidgetSystem widgetAlignSystem *WidgetAlignSystem - pluginSystem *PluginSystem + plugins *Plugins updatedAt time.Time property id.PropertyID clusters *ClusterList @@ -78,11 +78,11 @@ func (s *Scene) WidgetAlignSystem() *WidgetAlignSystem { return s.widgetAlignSystem } -func (s *Scene) PluginSystem() *PluginSystem { +func (s *Scene) Plugins() *Plugins { if s == nil { return nil } - return s.pluginSystem + return s.plugins } func (s *Scene) UpdatedAt() time.Time { @@ -116,7 +116,7 @@ func (s *Scene) Properties() []id.PropertyID { return nil } ids := []id.PropertyID{s.property} - ids = append(ids, s.pluginSystem.Properties()...) + ids = append(ids, s.plugins.Properties()...) ids = append(ids, s.widgetSystem.Properties()...) return ids } diff --git a/pkg/scene/scene_test.go b/pkg/scene/scene_test.go index f72a0ea2..3e789454 100644 --- a/pkg/scene/scene_test.go +++ b/pkg/scene/scene_test.go @@ -91,7 +91,7 @@ func TestSceneNil(t *testing.T) { assert.True(t, s.Team().IsNil()) assert.True(t, s.RootLayer().IsNil()) assert.True(t, s.CreatedAt().IsZero()) - assert.Nil(t, s.PluginSystem()) + assert.Nil(t, s.Plugins()) assert.True(t, s.Property().IsNil()) } diff --git a/pkg/scene/sceneops/plugin_migrator.go b/pkg/scene/sceneops/plugin_migrator.go index 7c2c3a51..26950465 100644 --- a/pkg/scene/sceneops/plugin_migrator.go +++ b/pkg/scene/sceneops/plugin_migrator.go @@ -43,7 +43,7 @@ func (s *PluginMigrator) MigratePlugins(ctx context.Context, sc *scene.Scene, ol return MigratePluginsResult{}, ErrInvalidPlugins } - if !sc.PluginSystem().Has(oldPluginID) { + if !sc.Plugins().Has(oldPluginID) { return MigratePluginsResult{}, ErrPluginNotInstalled } @@ -101,8 +101,8 @@ func (s *PluginMigrator) MigratePlugins(ctx context.Context, sc *scene.Scene, ol } // シーンのプラグイン - sc.PluginSystem().Upgrade(oldPluginID, newPluginID, nil, false) - for _, sp := range sc.PluginSystem().Plugins() { + sc.Plugins().Upgrade(oldPluginID, newPluginID, nil, false) + for _, sp := range sc.Plugins().Plugins() { if sp.Plugin().Equal(newPluginID) && sp.Property() != nil { propertyIDs = append(propertyIDs, *sp.Property()) } From 44555405948bdd28dfcda94f0df6790d7d02c31f Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 12 Jan 2022 21:04:22 +0900 Subject: [PATCH 54/55] impl usecase --- internal/infrastructure/memory/layer.go | 44 +++++ internal/infrastructure/mongo/layer.go | 19 ++ internal/usecase/interactor/plugin.go | 2 + internal/usecase/interactor/plugin_delete.go | 6 +- internal/usecase/interactor/plugin_upload.go | 183 ++++++++++++++++++- internal/usecase/repo/layer.go | 2 + 6 files changed, 246 insertions(+), 10 deletions(-) diff --git a/internal/infrastructure/memory/layer.go b/internal/infrastructure/memory/layer.go index c410e927..98a20e39 100644 --- a/internal/infrastructure/memory/layer.go +++ b/internal/infrastructure/memory/layer.go @@ -137,6 +137,50 @@ func (r *Layer) FindGroupBySceneAndLinkedDatasetSchema(ctx context.Context, s id return result, nil } +func (r *Layer) FindParentsByIDs(_ context.Context, ids []id.LayerID, scenes []id.SceneID) (layer.GroupList, error) { + r.lock.Lock() + defer r.lock.Unlock() + + res := layer.GroupList{} + for _, l := range r.data { + if !isSceneIncludes(l.Scene(), scenes) { + continue + } + gl, ok := l.(*layer.Group) + if !ok { + continue + } + for _, cl := range gl.Layers().Layers() { + if cl.Contains(ids) { + res = append(res, gl) + } + } + } + + return res, nil +} + +func (r *Layer) FindByPluginAndExtension(_ context.Context, pid id.PluginID, eid *id.PluginExtensionID, scenes []id.SceneID) (layer.List, error) { + r.lock.Lock() + defer r.lock.Unlock() + + res := layer.List{} + for _, l := range r.data { + if !isSceneIncludes(l.Scene(), scenes) { + continue + } + + if l.Plugin().Equal(pid) { + e := l.Extension() + if eid == nil || e != nil && *e == *eid { + res = append(res, &l) + } + } + } + + return res, nil +} + func (r *Layer) FindByProperty(ctx context.Context, id id.PropertyID, f []id.SceneID) (layer.Layer, error) { r.lock.Lock() defer r.lock.Unlock() diff --git a/internal/infrastructure/mongo/layer.go b/internal/infrastructure/mongo/layer.go index c2d7bce5..fb7e6748 100644 --- a/internal/infrastructure/mongo/layer.go +++ b/internal/infrastructure/mongo/layer.go @@ -108,6 +108,25 @@ func (r *layerRepo) FindGroupBySceneAndLinkedDatasetSchema(ctx context.Context, return r.findGroups(ctx, nil, filter) } +func (r *layerRepo) FindParentsByIDs(ctx context.Context, ids []id.LayerID, scenes []id.SceneID) (layer.GroupList, error) { + f := bson.M{ + "group.layers": bson.M{"$in": id.LayerIDToKeys(ids)}, + } + filter := r.sceneFilter(f, scenes) + return r.findGroups(ctx, nil, filter) +} + +func (r *layerRepo) FindByPluginAndExtension(ctx context.Context, pid id.PluginID, eid *id.PluginExtensionID, scenes []id.SceneID) (layer.List, error) { + f := bson.M{ + "plugin": pid.String(), + } + if eid != nil { + f["extension"] = eid.String() + } + filter := r.sceneFilter(f, scenes) + return r.find(ctx, nil, filter) +} + func (r *layerRepo) FindByProperty(ctx context.Context, id id.PropertyID, f []id.SceneID) (layer.Layer, error) { filter := r.sceneFilterD(bson.D{ {Key: "$or", Value: []bson.D{ diff --git a/internal/usecase/interactor/plugin.go b/internal/usecase/interactor/plugin.go index 3ea24883..b0a48aab 100644 --- a/internal/usecase/interactor/plugin.go +++ b/internal/usecase/interactor/plugin.go @@ -17,6 +17,7 @@ type Plugin struct { pluginRepo repo.Plugin propertySchemaRepo repo.PropertySchema propertyRepo repo.Property + layerRepo repo.Layer file gateway.File pluginRepository gateway.PluginRepository transaction repo.Transaction @@ -31,6 +32,7 @@ func NewPlugin(r *repo.Container, gr *gateway.Container) interfaces.Plugin { pluginRepo: r.Plugin, propertySchemaRepo: r.PropertySchema, propertyRepo: r.Property, + layerRepo: r.Layer, transaction: r.Transaction, pluginRepository: gr.PluginRepository, file: gr.File, diff --git a/internal/usecase/interactor/plugin_delete.go b/internal/usecase/interactor/plugin_delete.go index 4d2558e0..beb07834 100644 --- a/internal/usecase/interactor/plugin_delete.go +++ b/internal/usecase/interactor/plugin_delete.go @@ -37,10 +37,14 @@ func (i *Plugin) Delete(ctx context.Context, pid id.PluginID, operator *usecase. return interfaces.ErrOperationDenied } - if s.PluginSystem().HasPlugin(p.ID()) { + if s.Plugins().HasNamed(p.ID().Name()) { return interfaces.ErrCannotDeleteUsedPlugin } + if err := i.deleteLayersByPluginExtension(ctx, nil, p.ID(), nil); err != nil { + return err + } + if err := i.pluginRepo.Remove(ctx, p.ID()); err != nil { return err } diff --git a/internal/usecase/interactor/plugin_upload.go b/internal/usecase/interactor/plugin_upload.go index b934c751..da172eab 100644 --- a/internal/usecase/interactor/plugin_upload.go +++ b/internal/usecase/interactor/plugin_upload.go @@ -11,6 +11,7 @@ import ( "github.com/reearth/reearth-backend/internal/usecase/interfaces" "github.com/reearth/reearth-backend/pkg/id" "github.com/reearth/reearth-backend/pkg/plugin" + "github.com/reearth/reearth-backend/pkg/plugin/manifest" "github.com/reearth/reearth-backend/pkg/plugin/pluginpack" "github.com/reearth/reearth-backend/pkg/plugin/repourl" "github.com/reearth/reearth-backend/pkg/property" @@ -71,7 +72,7 @@ func (i *Plugin) Upload(ctx context.Context, r io.Reader, sid id.SceneID, operat return nil, nil, rerror.ErrInternalBy(err) } - if err := i.installPlugin(ctx, p, s); err != nil { + if err := i.installScenePlugin(ctx, p, s); err != nil { return nil, nil, rerror.ErrInternalBy(err) } @@ -127,12 +128,25 @@ func (i *Plugin) UploadFromRemote(ctx context.Context, u *url.URL, sid id.SceneI return nil, nil, interfaces.ErrInvalidPluginPackage } - if p, err := i.pluginRepo.FindByID(ctx, p.Manifest.Plugin.ID(), []id.SceneID{sid}); err != nil && !errors.Is(err, rerror.ErrNotFound) { + newpid := p.Manifest.Plugin.ID() + oldpid := s.Plugins().PluginByName(newpid.Name()).PluginRef() + oldp, err := i.pluginRepo.FindByID(ctx, newpid, []id.SceneID{sid}) + if err != nil && !errors.Is(err, rerror.ErrNotFound) { return nil, nil, err - } else if p != nil { - return nil, nil, interfaces.ErrPluginAlreadyInstalled } + // new (oldpid == nil): upload files, save plugin and properties -> install + // same (oldpid.Equal(newpid)): delete old files -> upload files, save plugin and property schemas -> migrate + // diff (!oldpid.Equal(newpid)): upload files, save plugin and property schemas -> migrate -> delete old files + + if oldpid != nil && oldpid.Equal(newpid) { + // same only: delete old files + if err := i.file.RemovePlugin(ctx, *oldpid); err != nil { + return nil, nil, err + } + } + + // uploads files for { f, err := p.Files.Next() if err != nil { @@ -146,25 +160,42 @@ func (i *Plugin) UploadFromRemote(ctx context.Context, u *url.URL, sid id.SceneI } } + // save plugin and property schemas if ps := p.Manifest.PropertySchemas(); len(ps) > 0 { if err := i.propertySchemaRepo.SaveAll(ctx, ps); err != nil { return nil, nil, err } } + if err := i.pluginRepo.Save(ctx, p.Manifest.Plugin); err != nil { return nil, nil, err } - if err := i.installPlugin(ctx, p, s); err != nil { - return nil, nil, err + if oldpid == nil { + // new: install plugin + if err := i.installScenePlugin(ctx, p, s); err != nil { + return nil, nil, err + } + } else { + // same, diff: migrate + if err := i.migrateScenePlugin(ctx, p, s, oldp); err != nil { + return nil, nil, err + } + } + + if oldpid != nil && !oldpid.Equal(newpid) { + // diff only: delete old files + if err := i.file.RemovePlugin(ctx, *oldpid); err != nil { + return nil, nil, err + } } tx.Commit() return p.Manifest.Plugin, s, nil } -// installPlugin installs the plugin to the scene -func (i *Plugin) installPlugin(ctx context.Context, p *pluginpack.Package, s *scene.Scene) (err error) { +// installScenePlugin installs the plugin to the scene +func (i *Plugin) installScenePlugin(ctx context.Context, p *pluginpack.Package, s *scene.Scene) (err error) { var ppid *id.PropertyID var pp *property.Property if psid := p.Manifest.Plugin.Schema(); psid != nil { @@ -173,7 +204,7 @@ func (i *Plugin) installPlugin(ctx context.Context, p *pluginpack.Package, s *sc return err } } - s.PluginSystem().Add(scene.NewPlugin(p.Manifest.Plugin.ID(), ppid)) + s.Plugins().Add(scene.NewPlugin(p.Manifest.Plugin.ID(), ppid)) if pp != nil { if err := i.propertyRepo.Save(ctx, pp); err != nil { @@ -185,3 +216,137 @@ func (i *Plugin) installPlugin(ctx context.Context, p *pluginpack.Package, s *sc } return nil } + +func (i *Plugin) migrateScenePlugin(ctx context.Context, p *pluginpack.Package, s *scene.Scene, oldp *plugin.Plugin) (err error) { + if oldp == nil || p.Manifest == nil { + return nil + } + + oldPManifest, err := i.pluginManifestFromPlugin(ctx, oldp) + if err != nil { + return err + } + + diff := manifest.DiffFrom(oldPManifest, *p.Manifest) + if diff.IsEmpty() { + return nil + } + + updatedProperties := property.List{} + + // update scene + var spp *id.PropertyID + if to := diff.PropertySchemaDiff.To; !to.IsNil() && diff.PropertySchemaDiff.From.IsNil() { + // new plugin property + p, err := property.New().NewID().Scene(s.ID()).Schema(to).Build() + if err != nil { + return err + } + spp = p.ID().Ref() + updatedProperties = append(updatedProperties, p) + } + + sp := s.Plugins().Plugin(diff.From) + if sp != nil && sp.Property() != nil && diff.PropertySchemaDeleted { + // plugin property should be removed + if err := i.propertyRepo.Remove(ctx, *sp.Property()); err != nil { + return err + } + } + + s.Plugins().Upgrade(diff.From, diff.To, spp, diff.PropertySchemaDeleted) + if err := i.sceneRepo.Save(ctx, s); err != nil { + return err + } + + // delete layers + for _, e := range diff.DeletedExtensions { + if err := i.deleteLayersByPluginExtension(ctx, s.ID().Ref(), diff.From, &e.ExtensionID); err != nil { + return err + } + } + + // migrate properties + updatedPropertySchemas := diff.PropertySchmaDiffs() + for _, e := range updatedPropertySchemas { + properties, err := i.propertyRepo.FindBySchema(ctx, []id.PropertySchemaID{e.From}, s.ID()) + if err != nil { + return err + } + for _, p := range properties { + if e.Migrate(p) { + updatedProperties = append(updatedProperties, p) + } + } + } + + // save properties + if len(updatedProperties) > 0 { + if err := i.propertyRepo.SaveAll(ctx, updatedProperties); err != nil { + return err + } + } + + // delete unused schemas and properties + if deleted := diff.DeletedPropertySchemas(); len(deleted) > 0 { + if err := i.propertySchemaRepo.RemoveAll(ctx, deleted); err != nil { + return err + } + } + + return nil +} + +func (i *Plugin) deleteLayersByPluginExtension(ctx context.Context, sid *id.SceneID, p id.PluginID, e *id.PluginExtensionID) error { + var scenes []id.SceneID + if sid != nil { + scenes = []id.SceneID{*sid} + } + + // delete layers + deletedLayers := []id.LayerID{} + layers, err := i.layerRepo.FindByPluginAndExtension(ctx, p, e, scenes) + if err != nil { + return err + } + deletedLayers = append(deletedLayers, layers.IDs().Layers()...) + + // update parent layer + parentLayers, err := i.layerRepo.FindParentsByIDs(ctx, deletedLayers, scenes) + if err != nil { + return err + } + + for _, p := range parentLayers { + p.Layers().RemoveLayer(deletedLayers...) + } + if err := i.layerRepo.SaveAll(ctx, parentLayers.ToLayerList()); err != nil { + return err + } + if err := i.layerRepo.RemoveAll(ctx, deletedLayers); err != nil { + return err + } + if err := i.propertyRepo.RemoveAll(ctx, layers.Properties()); err != nil { + return err + } + + return nil +} + +func (i *Plugin) pluginManifestFromPlugin(ctx context.Context, p *plugin.Plugin) (manifest.Manifest, error) { + schemas, err := i.propertySchemaRepo.FindByIDs(ctx, p.PropertySchemas()) + if err != nil { + return manifest.Manifest{}, err + } + + var s *property.Schema + if ps := p.Schema(); ps != nil { + s = schemas.Find(*ps) + } + + return manifest.Manifest{ + Plugin: p, + ExtensionSchema: schemas, + Schema: s, + }, nil +} diff --git a/internal/usecase/repo/layer.go b/internal/usecase/repo/layer.go index 75b134bf..272f2a7d 100644 --- a/internal/usecase/repo/layer.go +++ b/internal/usecase/repo/layer.go @@ -17,6 +17,8 @@ type Layer interface { FindGroupByIDs(context.Context, []id.LayerID, []id.SceneID) (layer.GroupList, error) FindGroupBySceneAndLinkedDatasetSchema(context.Context, id.SceneID, id.DatasetSchemaID) (layer.GroupList, error) FindParentByID(context.Context, id.LayerID, []id.SceneID) (*layer.Group, error) + FindParentsByIDs(context.Context, []id.LayerID, []id.SceneID) (layer.GroupList, error) + FindByPluginAndExtension(context.Context, id.PluginID, *id.PluginExtensionID, []id.SceneID) (layer.List, error) FindByProperty(context.Context, id.PropertyID, []id.SceneID) (layer.Layer, error) FindByScene(context.Context, id.SceneID) (layer.List, error) FindByTag(context.Context, id.TagID, []id.SceneID) (layer.List, error) From 15763092260e60ceaab5dfd99a190dbf4a33f7b7 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Thu, 13 Jan 2022 16:12:57 +0900 Subject: [PATCH 55/55] fix mocking NewItemID --- pkg/property/diff_test.go | 7 ++++++- pkg/property/id_test.go | 9 +++++++++ pkg/property/property_test.go | 6 +++--- 3 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 pkg/property/id_test.go diff --git a/pkg/property/diff_test.go b/pkg/property/diff_test.go index be462430..a694e017 100644 --- a/pkg/property/diff_test.go +++ b/pkg/property/diff_test.go @@ -134,7 +134,9 @@ func TestSchemaDiffFrom(t *testing.T) { } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() assert.Equal(t, tt.want, SchemaDiffFrom(tt.args.old, tt.args.new)) }) } @@ -234,7 +236,7 @@ func TestSchemaDiffFromProperty(t *testing.T) { func TestSchemaDiff_Migrate(t *testing.T) { itemID := NewItemID() - NewItemID = func() ItemID { return itemID } + newSchemaID := MustSchemaID("x~1.0.0/ax") tests := []struct { @@ -469,7 +471,10 @@ func TestSchemaDiff_Migrate(t *testing.T) { } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() + defer mockNewItemID(itemID)() assert.Equal(t, tt.want, tt.target.Migrate(tt.args)) assert.Equal(t, tt.wantProperty, tt.args) }) diff --git a/pkg/property/id_test.go b/pkg/property/id_test.go new file mode 100644 index 00000000..137bb595 --- /dev/null +++ b/pkg/property/id_test.go @@ -0,0 +1,9 @@ +package property + +func mockNewItemID(id ItemID) func() { + original := NewItemID + NewItemID = func() ItemID { return id } + return func() { + NewItemID = original + } +} diff --git a/pkg/property/property_test.go b/pkg/property/property_test.go index 21d7cbd7..abcd4f6f 100644 --- a/pkg/property/property_test.go +++ b/pkg/property/property_test.go @@ -975,9 +975,6 @@ func TestProperty_Item(t *testing.T) { func TestProperty_GetOrCreateRootGroup(t *testing.T) { itemID := NewItemID() - NewItemID = func() ItemID { - return itemID - } tests := []struct { name string @@ -1062,7 +1059,10 @@ func TestProperty_GetOrCreateRootGroup(t *testing.T) { } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() + defer mockNewItemID(itemID)() res1, res2 := tt.target.GetOrCreateRootGroup(tt.args) assert.Equal(t, tt.want1, res1) assert.Equal(t, tt.want2, res2)