diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 00000000..13566b81
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 00000000..37ebeea2
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ sqlite.xerial
+ true
+ org.sqlite.JDBC
+ jdbc:sqlite:$PROJECT_DIR$/tracker.db
+
+
+
+ $ProjectFileDir$
+
+
+
\ No newline at end of file
diff --git a/.idea/go-db-sql-final.iml b/.idea/go-db-sql-final.iml
new file mode 100644
index 00000000..5e764c4f
--- /dev/null
+++ b/.idea/go-db-sql-final.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 00000000..b152728e
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000..35eb1ddf
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/1 b/1
new file mode 100644
index 00000000..58c9bdf9
--- /dev/null
+++ b/1
@@ -0,0 +1 @@
+111
diff --git a/main.go b/main.go
index 44c32b3f..3e2befd2 100644
--- a/main.go
+++ b/main.go
@@ -97,9 +97,14 @@ func (s ParcelService) Delete(number int) error {
}
func main() {
- // настройте подключение к БД
+ db, err := sql.Open("sqlite", "tracker.db")
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ defer db.Close() // настройте подключение к БД
- store := // создайте объект ParcelStore функцией NewParcelStore
+ store := NewParcelStore(db) // создайте объект ParcelStore функцией NewParcelStore
service := NewParcelService(store)
// регистрация посылки
diff --git a/parcel.go b/parcel.go
index db6c815d..b1d2d8f4 100644
--- a/parcel.go
+++ b/parcel.go
@@ -2,6 +2,7 @@ package main
import (
"database/sql"
+ "fmt"
)
type ParcelStore struct {
@@ -13,48 +14,125 @@ func NewParcelStore(db *sql.DB) ParcelStore {
}
func (s ParcelStore) Add(p Parcel) (int, error) {
- // реализуйте добавление строки в таблицу parcel, используйте данные из переменной p
-
- // верните идентификатор последней добавленной записи
- return 0, nil
+ // SQL-запрос для добавления новой записи в таблицу parcel
+ query := `INSERT INTO parcel (client, status, address, created_at)
+ VALUES (:client, :status, :address, :created_at)`
+
+ // Выполнение запроса
+ result, err := s.db.Exec(query, sql.Named("client", p.Client), sql.Named("status", p.Status),
+ sql.Named("address", p.Address), sql.Named("created_at", p.CreatedAt))
+ if err != nil {
+ return 0, err
+ }
+
+ // Получение идентификатора добавленной записи
+ id, err := result.LastInsertId()
+ if err != nil {
+ return 0, err
+ }
+
+ return int(id), nil
}
func (s ParcelStore) Get(number int) (Parcel, error) {
- // реализуйте чтение строки по заданному number
- // здесь из таблицы должна вернуться только одна строка
-
- // заполните объект Parcel данными из таблицы
- p := Parcel{}
+ // SQL-запрос для получения одной записи по номеру посылки
+ query := `SELECT number, client, status, address, created_at FROM parcel WHERE number = :number`
+
+ // Выполнение запроса
+ row := s.db.QueryRow(query, sql.Named("number", number))
+
+ // Создание объекта для заполнения данными из БД
+ var p Parcel
+ err := row.Scan(&p.Number, &p.Client, &p.Status, &p.Address, &p.CreatedAt)
+ if err != nil {
+ if err == sql.ErrNoRows {
+ return p, fmt.Errorf("посылка с номером %d не найдена", number)
+ }
+ return p, err
+ }
return p, nil
}
func (s ParcelStore) GetByClient(client int) ([]Parcel, error) {
- // реализуйте чтение строк из таблицы parcel по заданному client
- // здесь из таблицы может вернуться несколько строк
-
- // заполните срез Parcel данными из таблицы
- var res []Parcel
-
- return res, nil
+ // SQL-запрос для получения всех посылок по клиенту
+ query := `SELECT number, client, status, address, created_at FROM parcel WHERE client = :client`
+
+ // Выполнение запроса
+ rows, err := s.db.Query(query, sql.Named("client", client))
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ // Срез для хранения полученных посылок
+ var parcels []Parcel
+
+ // Чтение всех строк из результата запроса
+ for rows.Next() {
+ var p Parcel
+ err := rows.Scan(&p.Number, &p.Client, &p.Status, &p.Address, &p.CreatedAt)
+ if err != nil {
+ return nil, err
+ }
+ parcels = append(parcels, p)
+ }
+
+ // Проверка на наличие ошибок после завершения итерации
+ if err := rows.Err(); err != nil {
+ return nil, err
+ }
+
+ return parcels, nil
}
func (s ParcelStore) SetStatus(number int, status string) error {
- // реализуйте обновление статуса в таблице parcel
+ // SQL-запрос для обновления статуса посылки по её номеру
+ query := `UPDATE parcel SET status = :status WHERE number = :number`
+
+ // Выполнение запроса
+ _, err := s.db.Exec(query, sql.Named("status", status), sql.Named("number", number))
+ if err != nil {
+ return err
+ }
return nil
}
func (s ParcelStore) SetAddress(number int, address string) error {
- // реализуйте обновление адреса в таблице parcel
- // менять адрес можно только если значение статуса registered
+ // Получаем текущий статус посылки
+ parcel, err := s.Get(number)
+ if err != nil {
+ return err
+ }
+
+ // Если статус не "зарегистрирована", изменение адреса запрещено
+ if parcel.Status != ParcelStatusRegistered {
+ return fmt.Errorf("нельзя изменить адрес, так как статус посылки не 'зарегистрирован'")
+ }
+
+ // SQL-запрос для обновления адреса посылки по её номеру
+ query := `UPDATE parcel SET address = :address WHERE number = :number`
+ _, err = s.db.Exec(query, sql.Named("address", address), sql.Named("number", number))
+ if err != nil {
+ return err
+ }
return nil
}
func (s ParcelStore) Delete(number int) error {
- // реализуйте удаление строки из таблицы parcel
- // удалять строку можно только если значение статуса registered
-
+ // Выполняем запрос на удаление только если статус посылки 'registered'
+ _, err := s.db.Exec(
+ "DELETE FROM parcel WHERE number = :number AND status = :status",
+ sql.Named("number", number),
+ sql.Named("status", ParcelStatusRegistered),
+ )
+
+ if err != nil {
+ return fmt.Errorf("ошибка выполнения запроса на удаление: %w", err)
+ }
+
+ // Если ошибка не возникла, но ни одна строка не была затронута, значит посылка не найдена или её статус не 'registered'
return nil
}
diff --git a/parcel_test.go b/parcel_test.go
index d1b93827..9d4d900d 100644
--- a/parcel_test.go
+++ b/parcel_test.go
@@ -22,7 +22,7 @@ var (
func getTestParcel() Parcel {
return Parcel{
Client: 1000,
- Status: ParcelStatusRegistered,
+ Status: ParcelStatusRegistered, // используем константу "registered"
Address: "test",
CreatedAt: time.Now().UTC().Format(time.RFC3339),
}
@@ -31,57 +31,97 @@ func getTestParcel() Parcel {
// TestAddGetDelete проверяет добавление, получение и удаление посылки
func TestAddGetDelete(t *testing.T) {
// prepare
- db, err := // настройте подключение к БД
- store := NewParcelStore(db)
- parcel := getTestParcel()
+ db, err := sql.Open("sqlite", "tracker.db") // подключаемся к файлу tracker.db
+ require.NoError(t, err)
+ defer db.Close()
+
+ store := NewParcelStore(db) // создаем хранилище для работы с базой данных
+ parcel := getTestParcel() // создаем тестовую посылку
// add
- // добавьте новую посылку в БД, убедитесь в отсутствии ошибки и наличии идентификатора
+ id, err := store.Add(parcel) // добавляем новую посылку
+ require.NoError(t, err)
+ require.NotZero(t, id)
+ parcel.Number = id // сохраняем идентификатор посылки
// get
- // получите только что добавленную посылку, убедитесь в отсутствии ошибки
- // проверьте, что значения всех полей в полученном объекте совпадают со значениями полей в переменной parcel
+ retrievedParcel, err := store.Get(parcel.Number) // получаем посылку по идентификатору
+ require.NoError(t, err)
+ require.Equal(t, parcel.Client, retrievedParcel.Client)
+ require.Equal(t, ParcelStatusRegistered, retrievedParcel.Status) // проверяем статус "registered"
+ require.Equal(t, parcel.Address, retrievedParcel.Address)
+ require.Equal(t, parcel.CreatedAt, retrievedParcel.CreatedAt)
// delete
- // удалите добавленную посылку, убедитесь в отсутствии ошибки
- // проверьте, что посылку больше нельзя получить из БД
+ err = store.Delete(parcel.Number) // удаляем посылку
+ require.NoError(t, err)
+
+ _, err = store.Get(parcel.Number) // проверяем, что посылка удалена
+ require.Error(t, err)
}
// TestSetAddress проверяет обновление адреса
func TestSetAddress(t *testing.T) {
// prepare
- db, err := // настройте подключение к БД
+ db, err := sql.Open("sqlite", "tracker.db") // подключаемся к файлу tracker.db
+ require.NoError(t, err)
+ defer db.Close()
+
+ store := NewParcelStore(db)
+ parcel := getTestParcel()
// add
- // добавьте новую посылку в БД, убедитесь в отсутствии ошибки и наличии идентификатора
+ id, err := store.Add(parcel)
+ require.NoError(t, err)
+ require.NotZero(t, id)
+ parcel.Number = id
// set address
- // обновите адрес, убедитесь в отсутствии ошибки
newAddress := "new test address"
+ err = store.SetAddress(parcel.Number, newAddress)
+ require.NoError(t, err)
// check
- // получите добавленную посылку и убедитесь, что адрес обновился
+ updatedParcel, err := store.Get(parcel.Number)
+ require.NoError(t, err)
+ require.Equal(t, newAddress, updatedParcel.Address)
}
// TestSetStatus проверяет обновление статуса
func TestSetStatus(t *testing.T) {
// prepare
- db, err := // настройте подключение к БД
+ db, err := sql.Open("sqlite", "tracker.db") // подключаемся к файлу tracker.db
+ require.NoError(t, err)
+ defer db.Close()
+
+ store := NewParcelStore(db)
+ parcel := getTestParcel()
// add
- // добавьте новую посылку в БД, убедитесь в отсутствии ошибки и наличии идентификатора
+ id, err := store.Add(parcel)
+ require.NoError(t, err)
+ require.NotZero(t, id)
+ parcel.Number = id
// set status
- // обновите статус, убедитесь в отсутствии ошибки
+ newStatus := ParcelStatusSent // используем статус "sent"
+ err = store.SetStatus(parcel.Number, newStatus)
+ require.NoError(t, err)
// check
- // получите добавленную посылку и убедитесь, что статус обновился
+ updatedParcel, err := store.Get(parcel.Number)
+ require.NoError(t, err)
+ require.Equal(t, ParcelStatusSent, updatedParcel.Status) // проверяем статус "sent"
}
// TestGetByClient проверяет получение посылок по идентификатору клиента
func TestGetByClient(t *testing.T) {
// prepare
- db, err := // настройте подключение к БД
+ db, err := sql.Open("sqlite", "tracker.db") // подключаемся к файлу tracker.db
+ require.NoError(t, err)
+ defer db.Close()
+
+ store := NewParcelStore(db)
parcels := []Parcel{
getTestParcel(),
@@ -92,30 +132,31 @@ func TestGetByClient(t *testing.T) {
// задаём всем посылкам один и тот же идентификатор клиента
client := randRange.Intn(10_000_000)
- parcels[0].Client = client
- parcels[1].Client = client
- parcels[2].Client = client
+ for i := range parcels {
+ parcels[i].Client = client
+ }
// add
for i := 0; i < len(parcels); i++ {
- id, err := // добавьте новую посылку в БД, убедитесь в отсутствии ошибки и наличии идентификатора
-
- // обновляем идентификатор добавленной у посылки
+ id, err := store.Add(parcels[i])
+ require.NoError(t, err)
+ require.NotZero(t, id)
parcels[i].Number = id
-
- // сохраняем добавленную посылку в структуру map, чтобы её можно было легко достать по идентификатору посылки
parcelMap[id] = parcels[i]
}
// get by client
- storedParcels, err := // получите список посылок по идентификатору клиента, сохранённого в переменной client
- // убедитесь в отсутствии ошибки
- // убедитесь, что количество полученных посылок совпадает с количеством добавленных
+ storedParcels, err := store.GetByClient(client)
+ require.NoError(t, err)
+ require.Len(t, storedParcels, len(parcels))
// check
for _, parcel := range storedParcels {
- // в parcelMap лежат добавленные посылки, ключ - идентификатор посылки, значение - сама посылка
- // убедитесь, что все посылки из storedParcels есть в parcelMap
- // убедитесь, что значения полей полученных посылок заполнены верно
+ original, exists := parcelMap[parcel.Number]
+ require.True(t, exists)
+ require.Equal(t, original.Client, parcel.Client)
+ require.Equal(t, ParcelStatusRegistered, parcel.Status) // проверяем статус "registered"
+ require.Equal(t, original.Address, parcel.Address)
+ require.Equal(t, original.CreatedAt, parcel.CreatedAt)
}
}
diff --git a/tracker.db b/tracker.db
index b6ba48a1..7e80d28b 100644
Binary files a/tracker.db and b/tracker.db differ