Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go-db-sql-final task #171

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions .idea/dataSources.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/go-db-sql-final.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions 1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
111
9 changes: 7 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

// регистрация посылки
Expand Down
122 changes: 100 additions & 22 deletions parcel.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"database/sql"
"fmt"
)

type ParcelStore struct {
Expand All @@ -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
}
105 changes: 73 additions & 32 deletions parcel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
Expand All @@ -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(),
Expand All @@ -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)
}
}
Binary file modified tracker.db
Binary file not shown.