diff --git a/pkg/setup/item.go b/pkg/setup/item.go index 12ba05f5e0d2b4c2391c2f62d369e0488e714402..1953cf09b332b5e39c1558c5e80fbe803c51a8b8 100644 --- a/pkg/setup/item.go +++ b/pkg/setup/item.go @@ -26,7 +26,7 @@ type ( ItemOption = EntityOption[ItemConf, *items.Item] ItemConf struct { - PublishFunc func(s *Setup, item *items.Item) (*items.Item, bool) + PublishFunc func(s *Setup, item *items.Item, exists bool) (*items.Item, bool) encoded bool // Если запись загружена из файла, необходимо выполнить Decode перед установкой } ) @@ -45,17 +45,26 @@ func (ItemConf) Init(e *Entity[ItemConf, *items.Item]) { DeleteItemIfRemoveFlag()(e) } -// OverwriteItem перезаписывает элемент +// PublishItem публикует элемент. func PublishItem() ItemOption { return func(c *Item) { - c.Conf.PublishFunc = func(s *Setup, item *items.Item) (*items.Item, bool) { return item, true } + c.Conf.PublishFunc = func(_ *Setup, item *items.Item, _ bool) (*items.Item, bool) { return item, true } + } +} + +// PublishItemIfNotExists публикует элемент, если он отсутствовал в системе. +func PublishItemIfNotExists() ItemOption { + return func(c *Item) { + c.Conf.PublishFunc = func(_ *Setup, item *items.Item, exists bool) (*items.Item, bool) { + return item, !exists + } } } // DraftItem не публикует элемент, сохраняет его в черновике func DraftItem() ItemOption { return func(c *Item) { - c.Conf.PublishFunc = func(s *Setup, item *items.Item) (*items.Item, bool) { return item, false } + c.Conf.PublishFunc = func(_ *Setup, item *items.Item, _ bool) (*items.Item, bool) { return item, false } } } @@ -149,7 +158,9 @@ func (s *Setup) InstallItem(ctx context.Context, exists map[string]*items.Item, exist, itemExists := exists[item.ID] // Если элемент не существует, создаем его if !itemExists { - if item, publish := c.Conf.PublishFunc(s, item); publish { + var publish bool + item, publish = c.Conf.PublishFunc(s, item, itemExists) + if publish { return items.CreateAndPublishItem(ctx, s.content.Items, item) } if _, err := s.content.Items.Create(ctx, item); err != nil { @@ -160,7 +171,7 @@ func (s *Setup) InstallItem(ctx context.Context, exists map[string]*items.Item, // Если элемент существует, обновляем его if item, changed := c.UpdateFunc(s, exist, item); changed { - if _, publish := c.Conf.PublishFunc(s, item); publish { + if _, publish := c.Conf.PublishFunc(s, item, itemExists); publish { return items.UpdateAndPublishItem(ctx, s.content.Items, item) } if err := s.content.Items.Update(ctx, item); err != nil { diff --git a/pkg/setup/item_test.go b/pkg/setup/item_test.go index 0a128625e7871d20aad0bceff7561197e97c01ea..22461a05d142f20f3c6c22e6ea73c99d1a87ea02 100644 --- a/pkg/setup/item_test.go +++ b/pkg/setup/item_test.go @@ -359,3 +359,107 @@ func TestSetup_UpdateDraft(t *testing.T) { }) } } + +func TestPublishItemIfNotExists(t *testing.T) { + tests := []struct { + name string + items []*items.Item + itemsCall func(svc *itemsMock.Items) + wantErr assert.ErrorAssertionFunc + }{ + { + name: "Item not exists", + items: []*items.Item{ + { + ID: "1", + SpaceID: "space", + EnvID: "env", + CollectionID: "coll", + Data: map[string]any{"text": "test"}, + }, + }, + itemsCall: func(svc *itemsMock.Items) { + svc.On("Find", mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything).Return(nil, 0, nil).Once() + svc.On("Create", mock.Anything, &items.Item{ + ID: "1", + SpaceID: "space", + EnvID: "env", + CollectionID: "coll", + Data: map[string]any{"text": "test"}, + }).Return(&items.Item{ + ID: "1", + SpaceID: "space", + EnvID: "env", + CollectionID: "coll", + Data: map[string]any{"text": "test"}, + }, nil).Once() + svc.On("Publish", mock.Anything, &items.Item{ + ID: "1", + SpaceID: "space", + EnvID: "env", + CollectionID: "coll", + Data: map[string]any{"text": "test"}, + }).Return(nil).Once() + }, + wantErr: assert.NoError, + }, + { + name: "Item exists", + items: []*items.Item{ + { + ID: "1", + SpaceID: "space", + EnvID: "env", + CollectionID: "coll", + Data: map[string]any{}, + }, + }, + itemsCall: func(svc *itemsMock.Items) { + svc.On("Find", mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything). + Return([]*items.Item{{ + ID: "1", + SpaceID: "space", + EnvID: "env", + CollectionID: "coll", + Data: map[string]any{"text": "test"}, + }}, 1, nil).Once() + svc.On("Update", mock.Anything, &items.Item{ + ID: "1", + SpaceID: "space", + EnvID: "env", + CollectionID: "coll", + Data: map[string]any{}, + }).Return(nil).Once() + svc.On("Unpublish", mock.Anything, &items.Item{ + ID: "1", + SpaceID: "space", + EnvID: "env", + CollectionID: "coll", + Data: map[string]any{}, + }).Return(nil).Once() + }, + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + svc := itemsMock.NewItems(t) + if tt.itemsCall != nil { + tt.itemsCall(svc) + } + + s := NewSetup(&content.Content{Items: svc}, "space", "env", nil) + s.AddItems( + tt.items, + PublishItemIfNotExists(), + // Добавляем опцию обновления для проверки публикации, когда элемент уже существует + func(c *Entity[ItemConf, *items.Item]) { + c.UpdateFunc = func(_ *Setup, _, item *items.Item) (*items.Item, bool) { return item, true } + }, + ) + tt.wantErr(t, s.InstallItems(context.Background())) + }) + } +}