diff --git a/server/internal/usecase/interactor/scene_plugin.go b/server/internal/usecase/interactor/scene_plugin.go index 4a14085c8b..196ee7c884 100644 --- a/server/internal/usecase/interactor/scene_plugin.go +++ b/server/internal/usecase/interactor/scene_plugin.go @@ -220,6 +220,9 @@ func (i *Scene) UpgradePlugin(ctx context.Context, sid id.SceneID, oldPluginID, } result, err := pluginMigrator.MigratePlugins(ctx, s, oldPluginID, newPluginID) + if err != nil { + return nil, err + } if err := i.sceneRepo.Save(ctx, result.Scene); err != nil { return nil, err @@ -230,9 +233,6 @@ func (i *Scene) UpgradePlugin(ctx context.Context, sid id.SceneID, oldPluginID, if err := i.layerRepo.SaveAll(ctx, result.Layers); err != nil { return nil, err } - if err := i.layerRepo.RemoveAll(ctx, result.RemovedLayers); err != nil { - return nil, err - } if err := i.propertyRepo.RemoveAll(ctx, result.RemovedProperties); err != nil { return nil, err } diff --git a/server/internal/usecase/interactor/scene_plugin_test.go b/server/internal/usecase/interactor/scene_plugin_test.go index 5081af5a64..f87c40dfce 100644 --- a/server/internal/usecase/interactor/scene_plugin_test.go +++ b/server/internal/usecase/interactor/scene_plugin_test.go @@ -346,14 +346,24 @@ func TestScene_UpgradePlugin(t *testing.T) { pl2ps := property.NewSchema().ID(id.NewPropertySchemaID(pid2, "@")).MustBuild() psr := memory.NewPropertySchemaWith(pl1ps, pl2ps) - pl1 := plugin.New().ID(pid1).Schema(pl1ps.ID().Ref()).MustBuild() - pl2 := plugin.New().ID(pid2).Schema(pl2ps.ID().Ref()).MustBuild() + pl1 := plugin.New().ID(pid1).Schema(pl1ps.ID().Ref()).Extensions([]*plugin.Extension{ + plugin.NewExtension().ID("a").Type(plugin.ExtensionTypeBlock).Schema(pl1ps.ID()).MustBuild(), + }).MustBuild() + pl2 := plugin.New().ID(pid2).Schema(pl2ps.ID().Ref()).Extensions([]*plugin.Extension{ + plugin.NewExtension().ID("a").Type(plugin.ExtensionTypeBlock).Schema(pl2ps.ID()).MustBuild(), + }).MustBuild() pr := memory.NewPluginWith(pl1, pl2) pl1p := property.New().NewID().Scene(sid).Schema(*pl1.Schema()).MustBuild() - prr := memory.NewPropertyWith(pl1p) - - lr := memory.NewLayerWith() + pl2p := property.New().NewID().Scene(sid).Schema(*pl1.Schema()).MustBuild() + prr := memory.NewPropertyWith(pl1p, pl2p) + + ibf1 := layer.NewInfoboxField().NewID().Plugin(plugin.OfficialPluginID).Extension("textblock").Property(id.NewPropertyID()).MustBuild() + ibf2 := layer.NewInfoboxField().NewID().Plugin(pid1).Extension("a").Property(pl2p.ID()).MustBuild() + ib := layer.NewInfobox([]*layer.InfoboxField{ibf1, ibf2}, id.NewPropertyID()) + l1 := layer.New().NewID().Plugin(plugin.OfficialPluginID.Ref()).Scene(sid).Infobox(ib).Item().MustBuild() + l2 := layer.New().NewID().Plugin(plugin.OfficialPluginID.Ref()).Scene(sid).Group().Layers(layer.NewIDList([]layer.ID{l1.ID()})).MustBuild() + lr := memory.NewLayerWith(l1, l2) dsr := memory.NewDataset() @@ -384,14 +394,32 @@ func TestScene_UpgradePlugin(t *testing.T) { if tt.wantErr != nil { assert.Equal(tt.wantErr, err) assert.Nil(gotSc) - } else { - assert.NoError(err) - assert.Same(sc, gotSc) - assert.False(gotSc.Plugins().Has(tt.args.old)) - assert.True(gotSc.Plugins().Has(tt.args.new)) - p, _ := prr.FindByID(ctx, *gotSc.Plugins().Plugin(tt.args.new).Property()) - assert.Equal(*pl2.Schema(), p.Schema()) + return + } + + assert.NoError(err) + assert.Same(sc, gotSc) + assert.False(gotSc.Plugins().Has(tt.args.old)) + assert.True(gotSc.Plugins().Has(tt.args.new)) + p, _ := prr.FindByID(ctx, *gotSc.Plugins().Plugin(tt.args.new).Property()) + assert.Equal(*pl2.Schema(), p.Schema()) + + // layers plugin id should not be changed + ls, err := lr.FindByScene(ctx, sid) + assert.NoError(err) + for _, l := range ls { + assert.Equal(plugin.OfficialPluginID.Ref(), (*l).Plugin()) } + + // layer > infobox > field + ll1 := *ls.Find(l1.ID()) + assert.NotNil(ll1.Infobox().Field(ibf1.ID())) + assert.Equal(id.OfficialPluginID, ll1.Infobox().Field(ibf1.ID()).Plugin()) + assert.NotNil(ll1.Infobox().Field(ibf2.ID())) + assert.Equal(tt.args.new, ll1.Infobox().Field(ibf2.ID()).Plugin()) + prop, err := prr.FindByID(ctx, ll1.Infobox().Field(ibf2.ID()).Property()) + assert.NoError(err) + assert.Equal(tt.args.new, prop.Schema().Plugin()) }) } } diff --git a/server/pkg/id/property_schema_list.go b/server/pkg/id/property_schema_list.go new file mode 100644 index 0000000000..335a455020 --- /dev/null +++ b/server/pkg/id/property_schema_list.go @@ -0,0 +1,58 @@ +package id + +type PropertySchemaIDList []PropertySchemaID + +// Clone duplicates the PropertySchemaIDList +func (l PropertySchemaIDList) Clone() PropertySchemaIDList { + if l == nil { + return nil + } + l2 := make(PropertySchemaIDList, len(l)) + for i, id := range l { + l2[i] = id.Clone() + } + return l2 +} + +// Merge merges PropertySchemaIDList +func (l PropertySchemaIDList) Merge(l2 PropertySchemaIDList) PropertySchemaIDList { + if l == nil { + return l2.Clone() + } + l3 := l.Clone() + if l2 == nil { + return l3 + } + l3 = append(l3, l2...) + return l3 +} + +// MergeUnique merges PropertySchemaIDList +func (l PropertySchemaIDList) MergeUnique(l2 PropertySchemaIDList) PropertySchemaIDList { + if l == nil { + return l2.Clone() + } + l3 := l.Clone() + if l2 == nil { + return l3 + } + for _, id := range l2 { + if !l3.Contains(id) { + l3 = append(l3, id) + } + } + return l3 +} + +// Contains checks if PropertySchemaIDList contains PropertySchemaID +func (l PropertySchemaIDList) Contains(id PropertySchemaID) bool { + if l == nil { + return false + } + for _, id2 := range l { + if id2 == id { + return true + } + } + return false +} diff --git a/server/pkg/id/property_schema_list_test.go b/server/pkg/id/property_schema_list_test.go new file mode 100644 index 0000000000..434c4c465b --- /dev/null +++ b/server/pkg/id/property_schema_list_test.go @@ -0,0 +1,182 @@ +package id + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPropertySchemaIDList_Clone(t *testing.T) { + tests := []struct { + name string + l PropertySchemaIDList + want PropertySchemaIDList + }{ + { + name: "nil", + l: nil, + want: nil, + }, + { + name: "empty", + l: PropertySchemaIDList{}, + want: PropertySchemaIDList{}, + }, + { + name: "normal", + l: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + want: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.l.Clone() + assert.Equal(t, tt.want, got) + assert.NotSame(t, tt.want, got) + }) + } +} + +func TestPropertySchemaIDList_Contains(t *testing.T) { + type args struct { + id PropertySchemaID + } + tests := []struct { + name string + l PropertySchemaIDList + args args + want bool + }{ + { + name: "nil", + l: nil, + args: args{MustPropertySchemaID("hoge~0.1.0/a")}, + want: false, + }, + { + name: "empty", + l: PropertySchemaIDList{}, + args: args{MustPropertySchemaID("hoge~0.1.0/a")}, + want: false, + }, + { + name: "normal", + l: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + args: args{MustPropertySchemaID("hoge~0.1.0/a")}, + want: true, + }, + { + name: "not found", + l: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + args: args{MustPropertySchemaID("hoge~0.1.0/c")}, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equalf(t, tt.want, tt.l.Contains(tt.args.id), "Contains(%v)", tt.args.id) + }) + } +} + +func TestPropertySchemaIDList_Merge(t *testing.T) { + type args struct { + l2 PropertySchemaIDList + } + tests := []struct { + name string + l PropertySchemaIDList + args args + want PropertySchemaIDList + }{ + { + name: "nil", + l: nil, + args: args{PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}}, + want: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + }, + { + name: "empty", + l: PropertySchemaIDList{}, + args: args{PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}}, + want: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + }, + { + name: "normal", + l: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + args: args{PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/c"), MustPropertySchemaID("hoge~0.1.0/d")}}, + want: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b"), MustPropertySchemaID("hoge~0.1.0/c"), MustPropertySchemaID("hoge~0.1.0/d")}, + }, + { + name: "duplicated", + l: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + args: args{PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}}, + want: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b"), MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + }, + { + name: "duplicated2", + l: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + args: args{PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/b"), MustPropertySchemaID("hoge~0.1.0/c")}}, + want: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b"), MustPropertySchemaID("hoge~0.1.0/b"), MustPropertySchemaID("hoge~0.1.0/c")}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.l.Merge(tt.args.l2)) + }) + } +} + +func TestPropertySchemaIDList_MergeUnique(t *testing.T) { + type args struct { + l2 PropertySchemaIDList + } + tests := []struct { + name string + l PropertySchemaIDList + args args + want PropertySchemaIDList + }{ + { + name: "nil", + l: nil, + args: args{PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}}, + want: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + }, + { + name: "empty", + l: PropertySchemaIDList{}, + args: args{PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}}, + want: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + }, + { + name: "normal", + l: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + args: args{PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/c"), MustPropertySchemaID("hoge~0.1.0/d")}}, + want: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b"), MustPropertySchemaID("hoge~0.1.0/c"), MustPropertySchemaID("hoge~0.1.0/d")}, + }, + { + name: "duplicated", + l: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + args: args{PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}}, + want: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + }, + { + name: "duplicated2", + l: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b")}, + args: args{PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/b"), MustPropertySchemaID("hoge~0.1.0/c")}}, + want: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/b"), MustPropertySchemaID("hoge~0.1.0/c")}, + }, + { + name: "duplicated3", + l: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/a")}, + args: args{PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/a")}}, + want: PropertySchemaIDList{MustPropertySchemaID("hoge~0.1.0/a"), MustPropertySchemaID("hoge~0.1.0/a")}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equalf(t, tt.want, tt.l.MergeUnique(tt.args.l2), "MergeUnique(%v)", tt.args.l2) + }) + } +} diff --git a/server/pkg/layer/id_list.go b/server/pkg/layer/id_list.go index 9d65bf45df..a29d1b044f 100644 --- a/server/pkg/layer/id_list.go +++ b/server/pkg/layer/id_list.go @@ -165,21 +165,23 @@ func (l *IDList) MoveLayerAt(fromIndex int, toIndex int) { l.layers = append(newSlice, l.layers[toIndex:]...) } -func (l *IDList) RemoveLayer(ids ...ID) { +func (l *IDList) RemoveLayer(ids ...ID) int { if l == nil { - return + return 0 } - + removed := 0 for i := 0; i < len(l.layers); i++ { layer := l.layers[i] for _, id := range ids { if layer == id { l.RemoveLayerAt(i) + removed++ i-- break } } } + return removed } func (l *IDList) RemoveLayerAt(index int) { diff --git a/server/pkg/layer/id_list_test.go b/server/pkg/layer/id_list_test.go index b2981981b4..1a50db5424 100644 --- a/server/pkg/layer/id_list_test.go +++ b/server/pkg/layer/id_list_test.go @@ -102,12 +102,13 @@ func TestLayerIDList(t *testing.T) { // 1, 3, 4 - layers.RemoveLayer(l2) + c := layers.RemoveLayer(l2) assert.Equal(t, 3, layers.LayerCount()) assert.Equal(t, l1, layers.LayerAt(0)) assert.Equal(t, l3, layers.LayerAt(1)) assert.Equal(t, l4, layers.LayerAt(2)) assert.False(t, layers.HasLayer(l2)) + assert.Equal(t, 1, c) // 1, 3, 4, 2 @@ -131,8 +132,9 @@ func TestLayerIDList(t *testing.T) { // 1, 3 - layers.RemoveLayer(l2, l4) + c = layers.RemoveLayer(l2, l4) assert.Equal(t, 2, layers.LayerCount()) assert.Equal(t, l1, layers.LayerAt(0)) assert.Equal(t, l3, layers.LayerAt(1)) + assert.Equal(t, 2, c) } diff --git a/server/pkg/layer/infobox_field.go b/server/pkg/layer/infobox_field.go index e9c5bd5101..5e695d3eaa 100644 --- a/server/pkg/layer/infobox_field.go +++ b/server/pkg/layer/infobox_field.go @@ -3,6 +3,7 @@ package layer import ( "errors" + "github.com/reearth/reearth/server/pkg/plugin" "github.com/reearth/reearth/server/pkg/property" ) @@ -51,3 +52,10 @@ func (i *InfoboxField) ValidateProperty(pm property.Map) error { return nil } + +func (i *InfoboxField) UpgradePlugin(id plugin.ID) { + if i == nil || !i.plugin.NameEqual(id) { + return + } + i.plugin = id +} diff --git a/server/pkg/layer/infobox_field_builder.go b/server/pkg/layer/infobox_field_builder.go index 47ce14ff06..ae3a0cc1ad 100644 --- a/server/pkg/layer/infobox_field_builder.go +++ b/server/pkg/layer/infobox_field_builder.go @@ -9,9 +9,7 @@ func NewInfoboxField() *InfoboxFieldBuilder { } func (b *InfoboxFieldBuilder) Build() (*InfoboxField, error) { - if b.i.id.IsNil() || - string(b.i.extension) == "" || - b.i.property.IsNil() { + if b.i.id.IsNil() || string(b.i.extension) == "" || b.i.property.IsNil() || b.i.plugin.IsNil() { return nil, ErrInvalidID } return b.i, nil diff --git a/server/pkg/layer/infobox_field_test.go b/server/pkg/layer/infobox_field_test.go new file mode 100644 index 0000000000..18e7020b35 --- /dev/null +++ b/server/pkg/layer/infobox_field_test.go @@ -0,0 +1,47 @@ +package layer + +import ( + "testing" + + "github.com/reearth/reearth/server/pkg/plugin" + "github.com/stretchr/testify/assert" +) + +func TestInfoboxField_UpgradePlugin(t *testing.T) { + type args struct { + id plugin.ID + } + tests := []struct { + name string + field *InfoboxField + args args + want plugin.ID + }{ + { + name: "normal", + field: &InfoboxField{ + plugin: MustPluginID("hoge~0.1.0"), + }, + args: args{ + id: MustPluginID("hoge~0.2.0"), + }, + want: MustPluginID("hoge~0.2.0"), + }, + { + name: "different", + field: &InfoboxField{ + plugin: MustPluginID("hoge~0.1.0"), + }, + args: args{ + id: MustPluginID("xyz~0.2.0"), + }, + want: MustPluginID("hoge~0.1.0"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.field.UpgradePlugin(tt.args.id) + assert.Equal(t, tt.want, tt.field.plugin) + }) + } +} diff --git a/server/pkg/layer/list.go b/server/pkg/layer/list.go index c43ce677d8..7a2eccc71c 100644 --- a/server/pkg/layer/list.go +++ b/server/pkg/layer/list.go @@ -153,6 +153,22 @@ func (ll List) Remove(lids ...ID) List { return res } +func (ll List) AddUnique(newList ...*Layer) List { + res := append(List{}, ll...) + + for _, l := range newList { + if l == nil { + continue + } + if res.Find((*l).ID()) != nil { + continue + } + res = append(res, l) + } + + return res +} + type ItemList []*Item func (ll ItemList) FindByDataset(ds DatasetID) *Item { diff --git a/server/pkg/layer/list_test.go b/server/pkg/layer/list_test.go index 01dc687727..4d0a7bc8b0 100644 --- a/server/pkg/layer/list_test.go +++ b/server/pkg/layer/list_test.go @@ -83,3 +83,12 @@ func TestList_Remove(t *testing.T) { assert.Equal(t, List(nil), List(nil).Remove(l1.ID())) assert.Equal(t, List{}, List{}.Remove(l1.ID())) } + +func TestList_AddUnique(t *testing.T) { + sid := NewSceneID() + l1 := NewItem().NewID().Scene(sid).MustBuild() + l2 := NewItem().NewID().Scene(sid).MustBuild() + assert.Equal(t, List{l2.LayerRef(), l1.LayerRef()}, List{l2.LayerRef()}.AddUnique(l1.LayerRef())) + assert.Equal(t, List{l2.LayerRef()}, List{l2.LayerRef()}.AddUnique(l2.LayerRef())) + assert.Equal(t, List{l1.LayerRef()}, List{}.AddUnique(l1.LayerRef(), l1.LayerRef())) +} diff --git a/server/pkg/plugin/id.go b/server/pkg/plugin/id.go index 1c57d8b4be..670fcbdc47 100644 --- a/server/pkg/plugin/id.go +++ b/server/pkg/plugin/id.go @@ -5,6 +5,7 @@ import "github.com/reearth/reearth/server/pkg/id" type ID = id.PluginID type ExtensionID = id.PluginExtensionID type PropertySchemaID = id.PropertySchemaID +type PropertySchemaIDList = id.PropertySchemaIDList type SceneID = id.SceneID var NewID = id.NewPluginID diff --git a/server/pkg/plugin/plugin.go b/server/pkg/plugin/plugin.go index 1e925a3d96..2b518e9388 100644 --- a/server/pkg/plugin/plugin.go +++ b/server/pkg/plugin/plugin.go @@ -96,7 +96,7 @@ func (p *Plugin) Schema() *PropertySchemaID { return p.schema } -func (p *Plugin) PropertySchemas() []PropertySchemaID { +func (p *Plugin) PropertySchemas() PropertySchemaIDList { if p == nil { return nil } diff --git a/server/pkg/plugin/plugin_test.go b/server/pkg/plugin/plugin_test.go index 45dee5e110..889de20f9d 100644 --- a/server/pkg/plugin/plugin_test.go +++ b/server/pkg/plugin/plugin_test.go @@ -51,22 +51,22 @@ func TestPlugin_PropertySchemas(t *testing.T) { tests := []struct { name string plugin *Plugin - expected []PropertySchemaID + expected PropertySchemaIDList }{ { name: "normal", plugin: New().ID(MustID("aaa~1.1.1")).Schema(&ps1).Extensions([]*Extension{NewExtension().ID("xxx").Schema(ps2).MustBuild(), NewExtension().ID("yyy").Schema(ps3).MustBuild()}).MustBuild(), - expected: []PropertySchemaID{ps1, ps2, ps3}, + expected: PropertySchemaIDList{ps1, ps2, ps3}, }, { name: "no plugin property schema", plugin: New().ID(MustID("aaa~1.1.1")).Extensions([]*Extension{NewExtension().ID("xxx").Schema(ps2).MustBuild(), NewExtension().ID("yyy").Schema(ps3).MustBuild()}).MustBuild(), - expected: []PropertySchemaID{ps2, ps3}, + expected: PropertySchemaIDList{ps2, ps3}, }, { name: "nil", plugin: nil, - expected: []PropertySchemaID(nil), + expected: PropertySchemaIDList(nil), }, } diff --git a/server/pkg/scene/plugins.go b/server/pkg/scene/plugins.go index 01e1e02281..524d5d06ef 100644 --- a/server/pkg/scene/plugins.go +++ b/server/pkg/scene/plugins.go @@ -88,25 +88,23 @@ func (p *Plugins) Remove(pid PluginID) { } func (p *Plugins) Upgrade(from, to PluginID, pr *PropertyID, deleteProperty bool) { - if p == nil || from.IsNil() || to.IsNil() { + if p == nil || from.IsNil() || to.IsNil() || from.Equal(to) || from.Equal(OfficialPluginID) { return } for i, p2 := range p.plugins { - if p2.plugin.Equal(OfficialPluginID) { + if !p2.plugin.Equal(from) { continue } - if p2.plugin.Equal(from) { - var newpr *PropertyID - if !deleteProperty { - newpr = pr.CloneRef() - if newpr == nil { - newpr = p2.property.CloneRef() - } + var newpr *PropertyID + if !deleteProperty { + newpr = pr.CloneRef() + if newpr == nil { + newpr = p2.property.CloneRef() } - p.plugins[i] = &Plugin{plugin: to, property: newpr} - return } + p.plugins[i] = &Plugin{plugin: to, property: newpr} + return } } diff --git a/server/pkg/scene/plugins_test.go b/server/pkg/scene/plugins_test.go index 38df11acad..f6d11379ec 100644 --- a/server/pkg/scene/plugins_test.go +++ b/server/pkg/scene/plugins_test.go @@ -450,6 +450,15 @@ func TestPlugins_Upgrade(t *testing.T) { target: NewPlugins([]*Plugin{NewPlugin(OfficialPluginID, pr)}), want: NewPlugins([]*Plugin{NewPlugin(OfficialPluginID, pr)}), }, + { + name: "same plugin", + args: args{ + From: pid, + To: pid, + }, + target: NewPlugins([]*Plugin{NewPlugin(OfficialPluginID, pr)}), + want: NewPlugins([]*Plugin{NewPlugin(OfficialPluginID, pr)}), + }, { name: "nil", args: args{ diff --git a/server/pkg/scene/sceneops/plugin_migrator.go b/server/pkg/scene/sceneops/plugin_migrator.go index 1526536b6f..1413e519da 100644 --- a/server/pkg/scene/sceneops/plugin_migrator.go +++ b/server/pkg/scene/sceneops/plugin_migrator.go @@ -24,13 +24,12 @@ type MigratePluginsResult struct { Scene *scene.Scene Layers layer.List Properties []*property.Property - RemovedLayers []layer.ID - RemovedProperties []property.ID + RemovedProperties property.IDList } var ( - ErrPluginNotInstalled error = errors.New("plugin not installed") - ErrInvalidPlugins error = errors.New("invalid plugins") + ErrPluginNotInstalled = errors.New("plugin not installed") + ErrInvalidPlugins = errors.New("invalid plugins") ) func (s *PluginMigrator) MigratePlugins(ctx context.Context, sc *scene.Scene, oldPluginID, newPluginID plugin.ID) (MigratePluginsResult, error) { @@ -38,14 +37,17 @@ func (s *PluginMigrator) MigratePlugins(ctx context.Context, sc *scene.Scene, ol return MigratePluginsResult{}, rerror.ErrInternalBy(errors.New("scene is nil")) } + // should be same plugin but different version if oldPluginID.Equal(newPluginID) || !oldPluginID.NameEqual(newPluginID) { return MigratePluginsResult{}, ErrInvalidPlugins } + // should be installed if !sc.Plugins().Has(oldPluginID) { return MigratePluginsResult{}, ErrPluginNotInstalled } + // Get plugins plugins, err := s.Plugin(ctx, []plugin.ID{oldPluginID, newPluginID}) if err != nil || len(plugins) < 2 { return MigratePluginsResult{}, ErrInvalidPlugins @@ -54,52 +56,23 @@ func (s *PluginMigrator) MigratePlugins(ctx context.Context, sc *scene.Scene, ol oldPlugin := plugins[0] newPlugin := plugins[1] - // 全レイヤーの取得 + // Get all layers layers, err := s.Layer(ctx, sc.ID()) if err != nil { return MigratePluginsResult{}, err } modifiedLayers := layer.List{} - removedLayers := []layer.ID{} - propertyIDs := []property.ID{} - removedPropertyIDs := []property.ID{} - schemaMap := map[property.SchemaID]*property.Schema{} + propertyIDs := property.IDList{} + removedPropertyIDs := property.IDList{} - // プロパティスキーマの取得と、古いスキーマと新しいスキーマのマップ作成 - schemaIDs := []property.SchemaID{} - if oldPlugin.Schema() != nil { - if pps := newPlugin.Schema(); pps != nil { - schemaIDs = append(schemaIDs, *pps) - } - } - for _, e := range newPlugin.Extensions() { - schemaIDs = append(schemaIDs, e.Schema()) - } - schemas, err := s.PropertySchema(ctx, schemaIDs...) + // Obtain property schema and map old schema to new schema + schemaMap, err := s.loadSchemas(ctx, oldPlugin, newPlugin) if err != nil { return MigratePluginsResult{}, err } - if oops := oldPlugin.Schema(); oops != nil { - if pps := newPlugin.Schema(); pps != nil { - for _, s := range schemas { - if s.ID() == *pps { - schemaMap[*oops] = s - } - } - } - } - for _, e := range oldPlugin.Extensions() { - if ne := newPlugin.Extension(e.ID()); ne != nil { - for _, s := range schemas { - if s.ID() == ne.Schema() { - schemaMap[e.Schema()] = s - } - } - } - } - // シーンのプラグイン + // Scene Plug-ins sc.Plugins().Upgrade(oldPluginID, newPluginID, nil, false) for _, sp := range sc.Plugins().Plugins() { if sp.Plugin().Equal(newPluginID) && sp.Property() != nil { @@ -107,7 +80,7 @@ func (s *PluginMigrator) MigratePlugins(ctx context.Context, sc *scene.Scene, ol } } - // シーンのウィジェット + // Scene widgets sc.Widgets().UpgradePlugin(oldPluginID, newPluginID) for _, w := range sc.Widgets().Widgets() { if w.Plugin().Equal(newPluginID) { @@ -119,97 +92,44 @@ func (s *PluginMigrator) MigratePlugins(ctx context.Context, sc *scene.Scene, ol } } - // レイヤー + // layers for _, l := range layers { if l == nil { continue } ll := *l - llp := ll.Plugin() - lle := ll.Extension() - - // 不正なレイヤーの検出 - if llp != nil && lle != nil && (*llp).Equal(oldPluginID) { - if newPlugin.Extension(*lle) == nil { - // 削除 - removedLayers = append(removedLayers, ll.ID()) - if p := ll.Property(); p != nil { - removedPropertyIDs = append(removedPropertyIDs, *p) - } - if ib := ll.Infobox(); ib != nil { - removedPropertyIDs = append(removedPropertyIDs, ib.Property()) - for _, f := range ib.Fields() { - removedPropertyIDs = append(removedPropertyIDs, f.Property()) - } - } - continue - } - } if p := ll.Property(); p != nil { propertyIDs = append(propertyIDs, *p) } - // 不正なInfoboxFieldの削除 - if ib := ll.Infobox(); ib != nil { - removeFields := []layer.InfoboxFieldID{} - for _, f := range ib.Fields() { - if newPlugin.Extension(f.Extension()) == nil { - removeFields = append(removeFields, f.ID()) - removedPropertyIDs = append(removedPropertyIDs, f.Property()) - } else { - propertyIDs = append(propertyIDs, f.Property()) - } - } - for _, f := range removeFields { - ib.Remove(f) - } - } - - ll.SetPlugin(&newPluginID) - modifiedLayers = append(modifiedLayers, l) - } - - // 不正なレイヤーのグループからの削除 - for _, lg := range layers.ToLayerGroupList() { - modified := false - canceled := false - for _, l := range removedLayers { - if l == lg.ID() { - canceled = true - break - } - if lg.Layers().HasLayer(l) { - lg.Layers().RemoveLayer(l) - modified = true - } - } - if canceled { + if ll.Infobox() == nil { continue } - if modified { - already := false - for _, l := range modifiedLayers { - if l != nil && (*l).ID() == lg.ID() { - already = true - break - } - } - if already { + + // Remove invalid Infobox Fields + for _, f := range ll.Infobox().Fields() { + if !f.Plugin().Equal(oldPlugin.ID()) { continue } - var lg2 layer.Layer = lg - modifiedLayers = append(modifiedLayers, &lg2) + modifiedLayers.AddUnique(l) + if newPlugin.Extension(f.Extension()) == nil { + ll.Infobox().Remove(f.ID()) + removedPropertyIDs = append(removedPropertyIDs, f.Property()) + } else { + f.UpgradePlugin(newPluginID) + propertyIDs = append(propertyIDs, f.Property()) + } } } - // プロパティの取得 + // Get all Properties properties, err := s.Property(ctx, propertyIDs...) if err != nil { return MigratePluginsResult{}, err } - // データセットの取得 + // Get all Datasets datasetIDs := collectDatasetIDs(properties) datasets, err := s.Dataset(ctx, datasetIDs...) if err != nil { @@ -217,7 +137,7 @@ func (s *PluginMigrator) MigratePlugins(ctx context.Context, sc *scene.Scene, ol } datasetLoader := datasets.Map().Loader() - // プロパティの移行作業 + // Migrate Properties for _, p := range properties { if schema := schemaMap[p.Schema()]; schema != nil { p.MigrateSchema(ctx, schema, datasetLoader) @@ -228,11 +148,38 @@ func (s *PluginMigrator) MigratePlugins(ctx context.Context, sc *scene.Scene, ol Scene: sc, Layers: modifiedLayers, Properties: properties, - RemovedLayers: removedLayers, RemovedProperties: removedPropertyIDs, }, nil } +func (s *PluginMigrator) loadSchemas(ctx context.Context, oldPlugin *plugin.Plugin, newPlugin *plugin.Plugin) (map[property.SchemaID]*property.Schema, error) { + schemasIDs := newPlugin.PropertySchemas().MergeUnique(oldPlugin.PropertySchemas()) + schemas, err := s.PropertySchema(ctx, schemasIDs...) + if err != nil { + return nil, err + } + schemaMap := map[property.SchemaID]*property.Schema{} + if opsId := oldPlugin.Schema(); opsId != nil { + if npsId := newPlugin.Schema(); npsId != nil { + for _, s := range schemas { + if s.ID() == *npsId { + schemaMap[*opsId] = s + } + } + } + } + for _, e := range oldPlugin.Extensions() { + if npe := newPlugin.Extension(e.ID()); npe != nil { + for _, s := range schemas { + if s.ID() == npe.Schema() { + schemaMap[e.Schema()] = s + } + } + } + } + return schemaMap, nil +} + func collectDatasetIDs(properties []*property.Property) []property.DatasetID { res := []property.DatasetID{} for _, p := range properties {