From 8e8b161f71dd98fd3196f41ca5ec2b06679fe8ed Mon Sep 17 00:00:00 2001 From: RD2W Date: Wed, 29 Oct 2025 00:14:00 +0300 Subject: [PATCH 1/2] feat: add slice storage and interface-based distribution --- cmd/notes/main.go | 44 ++--- internal/model/common.go | 6 + internal/model/note.go | 27 +++ internal/model/note_test.go | 141 +++++++++++++++ internal/repository/repository.go | 44 +++++ internal/repository/repository_test.go | 227 +++++++++++++++++++++++++ internal/service/service.go | 58 +++++++ internal/service/service_test.go | 150 ++++++++++++++++ 8 files changed, 671 insertions(+), 26 deletions(-) create mode 100644 internal/repository/repository.go create mode 100644 internal/repository/repository_test.go create mode 100644 internal/service/service.go create mode 100644 internal/service/service_test.go diff --git a/cmd/notes/main.go b/cmd/notes/main.go index afc3c27..7b5d395 100644 --- a/cmd/notes/main.go +++ b/cmd/notes/main.go @@ -6,25 +6,37 @@ import ( "time" "github.com/rd2w/go-notes/internal/model" + "github.com/rd2w/go-notes/internal/repository" + "github.com/rd2w/go-notes/internal/service" ) func main() { - note := model.NewNote("Первая заметка", "Это содержимое моей первой заметки") - displayNoteInfo("Исходная заметка:", note) - updateNote(note, "Обновленный заголовок", "Обновленное содержимое") - displayNoteInfo("После обновления:", note) + repo := repository.NewRepository() + svc := service.NewService(repo) + + log.Println("Запуск генерации тестовых данных...") + svc.StartDataGeneration(1 * time.Second) + + fmt.Printf("\n=== РЕЗУЛЬТАТЫ ===\n") + fmt.Printf("Всего заметок создано: %d\n", repo.GetNotesCount()) + + notes := repo.GetAllNotes() + for i, note := range notes { + displayNoteInfo(i, note) + } log.Println("Приложение \"Заметки\" успешно завершило выполнение программы!") } // displayNoteInfo отображает информацию о заметке в форматированном виде -func displayNoteInfo(header string, note *model.Note) { +func displayNoteInfo(count int, note *model.Note) { if note == nil { fmt.Println("Ошибка: заметка не существует") return } - fmt.Println(header) + fmt.Printf("\nЗаметка %d:\n", count+1) + fmt.Printf(" ID: %s\n", note.GetID()) fmt.Printf(" Заголовок: %s\n", note.GetTitle()) fmt.Printf(" Содержимое: %s\n", note.GetContent()) fmt.Printf(" Создана: %s\n", formatTime(note.GetCreatedAt())) @@ -32,26 +44,6 @@ func displayNoteInfo(header string, note *model.Note) { fmt.Println() } -// updateNote обновляет заголовок и содержимое заметки -func updateNote(note *model.Note, newTitle, newContent string) { - if note == nil { - fmt.Println("Ошибка: нельзя обновить несуществующую заметку!") - return - } - - fmt.Println("Обновление заметки...") - - if newTitle != "" { - note.SetTitle(newTitle) - } - - if newContent != "" { - note.SetContent(newContent) - } - - fmt.Printf("✅ Заметка успешно обновлена\n\n") -} - // formatTime форматирует время в едином стиле func formatTime(t time.Time) string { return t.Format("2006-01-02 15:04:05") diff --git a/internal/model/common.go b/internal/model/common.go index f0c4391..bcd3e78 100644 --- a/internal/model/common.go +++ b/internal/model/common.go @@ -2,6 +2,12 @@ package model import "time" +// Entity интерфейс, который должны реализовывать все сущности +type Entity interface { + GetID() string + GetType() string +} + // TimeFields содержит общие временные метки для сущностей type TimeFields struct { createdAt time.Time diff --git a/internal/model/note.go b/internal/model/note.go index 3c7af2c..17c61bd 100644 --- a/internal/model/note.go +++ b/internal/model/note.go @@ -1,8 +1,14 @@ package model +import ( + "crypto/rand" + "encoding/base64" +) + // Note представляет сущность заметки type Note struct { TimeFields + id string title string content string } @@ -10,6 +16,7 @@ type Note struct { // NewNote создает новую заметку с инициализацией временных меток func NewNote(title, content string) *Note { note := &Note{ + id: generateID(), title: title, content: content, } @@ -17,6 +24,16 @@ func NewNote(title, content string) *Note { return note } +// GetID возвращает идентификатор заметки (реализация интерфейса Entity) +func (n *Note) GetID() string { + return n.id +} + +// GetType возвращает тип сущности (реализация интерфейса Entity) +func (n *Note) GetType() string { + return "note" +} + // GetTitle возвращает заголовок заметки func (n *Note) GetTitle() string { return n.title @@ -38,3 +55,13 @@ func (n *Note) SetContent(newContent string) { n.content = newContent n.updateTimestamp() } + +// generateID генерирует уникальный идентификатор +func generateID() string { + b := make([]byte, 8) + _, err := rand.Read(b) + if err != nil { + panic("не удалось сгенерировать ID") + } + return base64.URLEncoding.EncodeToString(b) +} diff --git a/internal/model/note_test.go b/internal/model/note_test.go index 6e379e8..ee46487 100644 --- a/internal/model/note_test.go +++ b/internal/model/note_test.go @@ -1,6 +1,8 @@ package model import ( + "encoding/base64" + "fmt" "testing" "time" ) @@ -229,3 +231,142 @@ func TestMultipleNotes(t *testing.T) { t.Error("Modifying one note should not affect another") } } + +func TestNoteIDGeneration(t *testing.T) { + // Создаем несколько заметок и проверяем что у них разные ID + note1 := NewNote("Title 1", "Content 1") + note2 := NewNote("Title 2", "Content 2") + note3 := NewNote("Title 3", "Content 3") + + // Проверяем что ID не пустые + if note1.GetID() == "" { + t.Error("Note ID should not be empty") + } + + if note2.GetID() == "" { + t.Error("Note ID should not be empty") + } + + if note3.GetID() == "" { + t.Error("Note ID should not be empty") + } + + // Проверяем что все ID уникальны + ids := make(map[string]bool) + ids[note1.GetID()] = true + ids[note2.GetID()] = true + ids[note3.GetID()] = true + + if len(ids) != 3 { + t.Error("All note IDs should be unique") + } + + // Проверяем формат ID (base64 URL encoding) + id := note1.GetID() + _, err := base64.URLEncoding.DecodeString(id) + if err != nil { + t.Errorf("Note ID should be valid base64 URL encoding: %v", err) + } +} + +func TestNoteEntityInterface(t *testing.T) { + note := NewNote("Test Note", "Test Content") + + // Проверяем метод GetID + id := note.GetID() + if id == "" { + t.Error("GetID should return non-empty string") + } + + // Проверяем метод GetType + entityType := note.GetType() + if entityType != "note" { + t.Errorf("GetType should return 'note', got %q", entityType) + } + + // Проверяем что методы возвращают консистентные данные + if note.GetID() != id { + t.Error("GetID should return consistent value") + } + + if note.GetType() != entityType { + t.Error("GetType should return consistent value") + } +} + +func TestNoteImmutabilityOfID(t *testing.T) { + note := NewNote("Original Title", "Original Content") + originalID := note.GetID() + + // Изменяем другие поля + note.SetTitle("New Title") + note.SetContent("New Content") + + // ID должен остаться неизменным + if note.GetID() != originalID { + t.Error("Note ID should be immutable after creation") + } + + // Создаем новую заметку и проверяем что ID другой + newNote := NewNote("Another Title", "Another Content") + if newNote.GetID() == originalID { + t.Error("Different notes should have different IDs") + } +} + +func TestNoteIDLengthAndFormat(t *testing.T) { + note := NewNote("Test", "Content") + id := note.GetID() + + // Проверяем длину ID (base64 от 8 байт = 11 символов без padding или 12 с padding) + if len(id) != 11 && len(id) != 12 { + t.Errorf("Expected ID length 11 or 12, got %d for ID %q", len(id), id) + } + + // Проверяем что ID состоит из валидных base64 URL символов + isValidBase64URLChar := func(char rune) bool { + return (char >= 'A' && char <= 'Z') || + (char >= 'a' && char <= 'z') || + (char >= '0' && char <= '9') || + char == '-' || char == '_' || char == '=' + } + + for _, char := range id { + if !isValidBase64URLChar(char) { + t.Errorf("ID contains invalid base64 URL character: %c", char) + } + } +} + +func TestMultipleNoteCreationConsistency(t *testing.T) { + // Создаем несколько заметок и проверяем целостность данных + notes := make([]*Note, 10) + for i := 0; i < 10; i++ { + notes[i] = NewNote( + fmt.Sprintf("Note %d", i), + fmt.Sprintf("Content %d", i), + ) + } + + for i, note := range notes { + // Проверяем что все поля установлены корректно + expectedTitle := fmt.Sprintf("Note %d", i) + expectedContent := fmt.Sprintf("Content %d", i) + + if note.GetTitle() != expectedTitle { + t.Errorf("Note %d: expected title %q, got %q", i, expectedTitle, note.GetTitle()) + } + + if note.GetContent() != expectedContent { + t.Errorf("Note %d: expected content %q, got %q", i, expectedContent, note.GetContent()) + } + + if note.GetID() == "" { + t.Errorf("Note %d: ID should not be empty", i) + } + + if note.GetType() != "note" { + t.Errorf("Note %d: type should be 'note', got %q", i, note.GetType()) + } + } +} diff --git a/internal/repository/repository.go b/internal/repository/repository.go new file mode 100644 index 0000000..4b35e05 --- /dev/null +++ b/internal/repository/repository.go @@ -0,0 +1,44 @@ +package repository + +import ( + "fmt" + "log" + + "github.com/rd2w/go-notes/internal/model" +) + +// Repository управляет хранением различных сущностей +type Repository struct { + notes []*model.Note + // В будущем нужно добавить другие слайсы для других сущностей +} + +// NewRepository создает новый экземпляр репозитория +func NewRepository() *Repository { + return &Repository{ + notes: make([]*model.Note, 0), + } +} + +// Save принимает интерфейс Entity и сохраняет в соответствующий слайс +func (r *Repository) Save(entity model.Entity) error { + // Проверяем тип сущности и сохраняем в соответствующий слайс + switch entity := entity.(type) { + case *model.Note: + r.notes = append(r.notes, entity) + log.Printf("Заметка сохранена: ID=%s, Title=%s", entity.GetID(), entity.GetTitle()) + default: + return fmt.Errorf("неподдерживаемый тип сущности: %T", entity) + } + return nil +} + +// GetAllNotes возвращает все сохраненные заметки +func (r *Repository) GetAllNotes() []*model.Note { + return r.notes +} + +// GetNotesCount возвращает количество сохраненных заметок +func (r *Repository) GetNotesCount() int { + return len(r.notes) +} diff --git a/internal/repository/repository_test.go b/internal/repository/repository_test.go new file mode 100644 index 0000000..825c576 --- /dev/null +++ b/internal/repository/repository_test.go @@ -0,0 +1,227 @@ +package repository + +import ( + "testing" + + "github.com/rd2w/go-notes/internal/model" +) + +// MockEntity для тестирования неподдерживаемых сущностей +type MockEntity struct{} + +func (m *MockEntity) GetID() string { return "mock-id" } +func (m *MockEntity) GetType() string { return "mock-type" } + +func TestNewRepository(t *testing.T) { + repo := NewRepository() + + if repo == nil { + t.Fatal("NewRepository returned nil") + } + + if repo.notes == nil { + t.Error("Notes slice should be initialized") + } + + if len(repo.notes) != 0 { + t.Errorf("New repository should have 0 notes, got %d", len(repo.notes)) + } +} + +func TestSaveNote(t *testing.T) { + repo := NewRepository() + note := model.NewNote("Test Title", "Test Content") + + // Сохраняем заметку + err := repo.Save(note) + if err != nil { + t.Errorf("Save failed: %v", err) + } + + // Проверяем что заметка сохранилась + if repo.GetNotesCount() != 1 { + t.Errorf("Expected 1 note, got %d", repo.GetNotesCount()) + } + + // Проверяем что это именно та заметка + notes := repo.GetAllNotes() + if len(notes) != 1 { + t.Fatalf("Expected 1 note in GetAllNotes, got %d", len(notes)) + } + + if notes[0].GetID() != note.GetID() { + t.Error("Saved note ID doesn't match") + } + + if notes[0].GetTitle() != note.GetTitle() { + t.Error("Saved note title doesn't match") + } +} + +func TestSaveMultipleNotes(t *testing.T) { + repo := NewRepository() + + // Создаем и сохраняем несколько заметок + notes := []*model.Note{ + model.NewNote("Note 1", "Content 1"), + model.NewNote("Note 2", "Content 2"), + model.NewNote("Note 3", "Content 3"), + } + + for i, note := range notes { + err := repo.Save(note) + if err != nil { + t.Errorf("Failed to save note %d: %v", i, err) + } + } + + // Проверяем количество + if repo.GetNotesCount() != 3 { + t.Errorf("Expected 3 notes, got %d", repo.GetNotesCount()) + } + + // Проверяем что все заметки сохранились + allNotes := repo.GetAllNotes() + if len(allNotes) != 3 { + t.Fatalf("Expected 3 notes in GetAllNotes, got %d", len(allNotes)) + } + + // Проверяем целостность данных + for i, savedNote := range allNotes { + if savedNote.GetID() != notes[i].GetID() { + t.Errorf("Note %d ID mismatch", i) + } + if savedNote.GetTitle() != notes[i].GetTitle() { + t.Errorf("Note %d title mismatch", i) + } + } +} + +func TestSaveUnsupportedEntity(t *testing.T) { + repo := NewRepository() + mockEntity := &MockEntity{} + + // Пытаемся сохранить неподдерживаемую сущность + err := repo.Save(mockEntity) + if err == nil { + t.Error("Expected error for unsupported entity type") + } + + expectedError := "неподдерживаемый тип сущности: *repository.MockEntity" + if err.Error() != expectedError { + t.Errorf("Expected error %q, got %q", expectedError, err.Error()) + } + + // Проверяем что ничего не сохранилось + if repo.GetNotesCount() != 0 { + t.Errorf("Repository should be empty after failed save, got %d notes", repo.GetNotesCount()) + } +} + +func TestGetAllNotes(t *testing.T) { + repo := NewRepository() + + // Проверяем пустой репозиторий + emptyNotes := repo.GetAllNotes() + if len(emptyNotes) != 0 { + t.Errorf("GetAllNotes should return empty slice for new repository, got %d", len(emptyNotes)) + } + + // Добавляем заметки и проверяем + note1 := model.NewNote("Note 1", "Content 1") + note2 := model.NewNote("Note 2", "Content 2") + + // Обрабатываем ошибки при сохранении + if err := repo.Save(note1); err != nil { + t.Fatalf("Failed to save note1: %v", err) + } + if err := repo.Save(note2); err != nil { + t.Fatalf("Failed to save note2: %v", err) + } + + allNotes := repo.GetAllNotes() + if len(allNotes) != 2 { + t.Fatalf("Expected 2 notes, got %d", len(allNotes)) + } +} + +func TestGetNotesCount(t *testing.T) { + repo := NewRepository() + + // Проверяем начальное состояние + if count := repo.GetNotesCount(); count != 0 { + t.Errorf("New repository should have 0 notes, got %d", count) + } + + // Добавляем заметки и проверяем счетчик + if err := repo.Save(model.NewNote("Note 1", "Content 1")); err != nil { + t.Fatalf("Failed to save note 1: %v", err) + } + if count := repo.GetNotesCount(); count != 1 { + t.Errorf("Expected 1 note, got %d", count) + } + + if err := repo.Save(model.NewNote("Note 2", "Content 2")); err != nil { + t.Fatalf("Failed to save note 2: %v", err) + } + if count := repo.GetNotesCount(); count != 2 { + t.Errorf("Expected 2 notes, got %d", count) + } + + if err := repo.Save(model.NewNote("Note 3", "Content 3")); err != nil { + t.Fatalf("Failed to save note 3: %v", err) + } + if count := repo.GetNotesCount(); count != 3 { + t.Errorf("Expected 3 notes, got %d", count) + } +} + +func TestRepositoryIsolation(t *testing.T) { + // Проверяем что разные репозитории изолированы друг от друга + repo1 := NewRepository() + repo2 := NewRepository() + + note1 := model.NewNote("Repo1 Note", "Content") + note2 := model.NewNote("Repo2 Note", "Content") + + // Обрабатываем ошибки при сохранении + if err := repo1.Save(note1); err != nil { + t.Fatalf("Failed to save note1 in repo1: %v", err) + } + if err := repo2.Save(note2); err != nil { + t.Fatalf("Failed to save note2 in repo2: %v", err) + } + + // Проверяем изоляцию + if repo1.GetNotesCount() != 1 { + t.Errorf("Repo1 should have 1 note, got %d", repo1.GetNotesCount()) + } + if repo2.GetNotesCount() != 1 { + t.Errorf("Repo2 should have 1 note, got %d", repo2.GetNotesCount()) + } + + repo1Notes := repo1.GetAllNotes() + repo2Notes := repo2.GetAllNotes() + + if repo1Notes[0].GetID() != note1.GetID() { + t.Error("Repo1 contains wrong note") + } + if repo2Notes[0].GetID() != note2.GetID() { + t.Error("Repo2 contains wrong note") + } +} + +func TestSaveNilEntity(t *testing.T) { + repo := NewRepository() + + // Пытаемся сохранить nil + err := repo.Save(nil) + if err == nil { + t.Error("Expected error when saving nil entity") + } + + expectedError := "неподдерживаемый тип сущности: " + if err.Error() != expectedError { + t.Errorf("Expected error %q, got %q", expectedError, err.Error()) + } +} diff --git a/internal/service/service.go b/internal/service/service.go new file mode 100644 index 0000000..dea7e90 --- /dev/null +++ b/internal/service/service.go @@ -0,0 +1,58 @@ +package service + +import ( + "fmt" + "log" + "time" + + "github.com/rd2w/go-notes/internal/model" + "github.com/rd2w/go-notes/internal/repository" +) + +// Service содержит бизнес-логику приложения +type Service struct { + repo *repository.Repository +} + +// NewService создает новый экземпляр сервиса +func NewService(repo *repository.Repository) *Service { + return &Service{ + repo: repo, + } +} + +// StartDataGeneration запускает периодическое создание тестовых данных +func (s *Service) StartDataGeneration(interval time.Duration) { + if s.repo == nil { + log.Println("Ошибка: репозиторий не инициализирован") + return + } + + ticker := time.NewTicker(interval) + defer ticker.Stop() + + noteCounter := 1 + + for range ticker.C { + // Создаем новую заметку + title := fmt.Sprintf("Тестовая заметка %d", noteCounter) + content := fmt.Sprintf("Это содержимое тестовой заметки номер %d", noteCounter) + + note := model.NewNote(title, content) + + // Передаем в репозиторий + if err := s.repo.Save(note); err != nil { + log.Printf("Ошибка сохранения заметки: %v", err) + } else { + log.Printf("Сгенерирована заметка: %s", title) + } + + noteCounter++ + + // Останавливаем после создания 5 заметок для демонстрации + if noteCounter > 5 { + log.Println("Генерация тестовых данных завершена") + break + } + } +} diff --git a/internal/service/service_test.go b/internal/service/service_test.go new file mode 100644 index 0000000..93db898 --- /dev/null +++ b/internal/service/service_test.go @@ -0,0 +1,150 @@ +package service + +import ( + "fmt" + "testing" + "time" + + "github.com/rd2w/go-notes/internal/repository" +) + +func TestNewService(t *testing.T) { + repo := repository.NewRepository() + service := NewService(repo) + + if service == nil { + t.Fatal("NewService returned nil") + } + + if service.repo != repo { + t.Error("Service should use the provided repository") + } +} +func TestStartDataGeneration(t *testing.T) { + repo := repository.NewRepository() + service := NewService(repo) + + // Запускаем генерацию и ждем ее завершения СИНХРОННО + interval := 1 * time.Millisecond + service.StartDataGeneration(interval) // Запускаем в той же горутине + + // Теперь безопасно проверяем результаты + notesCount := repo.GetNotesCount() + if notesCount != 5 { + t.Errorf("Expected 5 notes, got %d", notesCount) + } + + // Проверяем содержимое заметок + notes := repo.GetAllNotes() + for i, note := range notes { + expectedTitle := fmt.Sprintf("Тестовая заметка %d", i+1) + expectedContent := fmt.Sprintf("Это содержимое тестовой заметки номер %d", i+1) + + if note.GetTitle() != expectedTitle { + t.Errorf("Note %d: expected title %q, got %q", i+1, expectedTitle, note.GetTitle()) + } + + if note.GetContent() != expectedContent { + t.Errorf("Note %d: expected content %q, got %q", i+1, expectedContent, note.GetContent()) + } + + // Проверяем что заметка имеет ID + if note.GetID() == "" { + t.Errorf("Note %d: ID should not be empty", i+1) + } + + // Проверяем временные метки + if note.GetCreatedAt().IsZero() { + t.Errorf("Note %d: CreatedAt should be set", i+1) + } + if note.GetUpdatedAt().IsZero() { + t.Errorf("Note %d: UpdatedAt should be set", i+1) + } + } +} + +func TestStartDataGenerationStopsAfterFiveNotes(t *testing.T) { + repo := repository.NewRepository() + service := NewService(repo) + + // Запускаем генерацию синхронно + interval := 1 * time.Millisecond + startTime := time.Now() + service.StartDataGeneration(interval) + + // Проверяем что выполнение заняло разумное время + executionTime := time.Since(startTime) + if executionTime > time.Second { + t.Errorf("Data generation should complete quickly, took %v", executionTime) + } + + // Проверяем что создалось ровно 5 заметок + notesCount := repo.GetNotesCount() + if notesCount != 5 { + t.Errorf("Expected exactly 5 notes, got %d", notesCount) + } +} + +func TestServiceIsolation(t *testing.T) { + // Тестируем что разные сервисы работают независимо + repo1 := repository.NewRepository() + repo2 := repository.NewRepository() + + service1 := NewService(repo1) + service2 := NewService(repo2) + + service1.StartDataGeneration(1 * time.Millisecond) + service2.StartDataGeneration(1 * time.Millisecond) + + // Оба репозитория должны иметь по 5 заметок + if repo1.GetNotesCount() != 5 { + t.Errorf("Repo1 should have 5 notes, got %d", repo1.GetNotesCount()) + } + if repo2.GetNotesCount() != 5 { + t.Errorf("Repo2 should have 5 notes, got %d", repo2.GetNotesCount()) + } + + // Заметки в разных репозиториях должны быть независимы + notes1 := repo1.GetAllNotes() + notes2 := repo2.GetAllNotes() + + for i := 0; i < 5; i++ { + if notes1[i].GetID() == notes2[i].GetID() { + t.Errorf("Notes in different repositories should have different IDs") + } + } +} + +func TestServiceWithNilRepository(t *testing.T) { + // Тестируем что сервис не паникует при работе с nil репозиторием + service := NewService(nil) + + // Запускаем синхронно - должно завершиться сразу + service.StartDataGeneration(1 * time.Millisecond) + + // Если не было паники - тест пройден +} + +func TestNoteCounterIncrementsCorrectly(t *testing.T) { + repo := repository.NewRepository() + service := NewService(repo) + + // Запускаем генерацию синхронно + service.StartDataGeneration(1 * time.Millisecond) + + // Проверяем что заметки имеют правильную нумерацию + notes := repo.GetAllNotes() + + for i, note := range notes { + expectedNumber := i + 1 + expectedTitle := fmt.Sprintf("Тестовая заметка %d", expectedNumber) + expectedContent := fmt.Sprintf("Это содержимое тестовой заметки номер %d", expectedNumber) + + if note.GetTitle() != expectedTitle { + t.Errorf("Note %d has wrong title: %q", expectedNumber, note.GetTitle()) + } + if note.GetContent() != expectedContent { + t.Errorf("Note %d has wrong content: %q", expectedNumber, note.GetContent()) + } + } +} From 0e3221b9b0f4db6063553c0eeb7250fc491140fd Mon Sep 17 00:00:00 2001 From: RD2W Date: Thu, 30 Oct 2025 10:57:06 +0300 Subject: [PATCH 2/2] refactor: move Entity interface to repository package - Move Entity interface from internal/model/common.go to internal/repository/repository.go - Interface now better aligns with repository layer responsibility - Remove empty common.go file from model package --- internal/model/common.go | 6 ------ internal/repository/repository.go | 8 +++++++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/model/common.go b/internal/model/common.go index bcd3e78..f0c4391 100644 --- a/internal/model/common.go +++ b/internal/model/common.go @@ -2,12 +2,6 @@ package model import "time" -// Entity интерфейс, который должны реализовывать все сущности -type Entity interface { - GetID() string - GetType() string -} - // TimeFields содержит общие временные метки для сущностей type TimeFields struct { createdAt time.Time diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 4b35e05..498eaec 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -7,6 +7,12 @@ import ( "github.com/rd2w/go-notes/internal/model" ) +// Entity интерфейс, который должны реализовывать все сущности +type Entity interface { + GetID() string + GetType() string +} + // Repository управляет хранением различных сущностей type Repository struct { notes []*model.Note @@ -21,7 +27,7 @@ func NewRepository() *Repository { } // Save принимает интерфейс Entity и сохраняет в соответствующий слайс -func (r *Repository) Save(entity model.Entity) error { +func (r *Repository) Save(entity Entity) error { // Проверяем тип сущности и сохраняем в соответствующий слайс switch entity := entity.(type) { case *model.Note: