From 69fc7ae00b6ef5ad40ff5c16b4716e24501492f5 Mon Sep 17 00:00:00 2001 From: mixa4045 Date: Fri, 23 May 2025 18:34:37 +0300 Subject: [PATCH 1/3] first commit --- main.go | 12 ++++++-- parcel.go | 72 ++++++++++++++++++++++++++++++++++++++++++--- parcel_test.go | 77 +++++++++++++++++++++++++++++++++++++++++++++---- tracker.db | Bin 61440 -> 61440 bytes 4 files changed, 148 insertions(+), 13 deletions(-) diff --git a/main.go b/main.go index 44c32b3f..bcf1c66e 100644 --- a/main.go +++ b/main.go @@ -97,9 +97,15 @@ func (s ParcelService) Delete(number int) error { } func main() { - // настройте подключение к БД - - store := // создайте объект ParcelStore функцией NewParcelStore + db, err := sql.Open("sqlite", "tracker.db") + if err != nil { + fmt.Println(err) + return + } + defer db.Close() + + // создайте объект ParcelStore функцией NewParcelStore + store := NewParcelStore(db) service := NewParcelService(store) // регистрация посылки diff --git a/parcel.go b/parcel.go index db6c815d..0f562118 100644 --- a/parcel.go +++ b/parcel.go @@ -14,33 +14,69 @@ func NewParcelStore(db *sql.DB) ParcelStore { func (s ParcelStore) Add(p Parcel) (int, error) { // реализуйте добавление строки в таблицу parcel, используйте данные из переменной p - + res, err := s.db.Exec("INSERT INTO parcel (client, status, address, created_at) VALUES (:client, :status, :address, :created_at)", + 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 + } // верните идентификатор последней добавленной записи - return 0, nil + id, err := res.LastInsertId() + if err != nil { + return 0, err + } + + return int(id), nil } func (s ParcelStore) Get(number int) (Parcel, error) { + p := Parcel{Number: number} // реализуйте чтение строки по заданному number // здесь из таблицы должна вернуться только одна строка + row := s.db.QueryRow("SELECT client, status, address, created_at FROM parcel WHERE number = :number", sql.Named("number", p.Number)) // заполните объект Parcel данными из таблицы - p := Parcel{} - + err := row.Scan(&p.Client, &p.Status, &p.Address, &p.CreatedAt) + if err != nil { + return p, err + } return p, nil } func (s ParcelStore) GetByClient(client int) ([]Parcel, error) { // реализуйте чтение строк из таблицы parcel по заданному client // здесь из таблицы может вернуться несколько строк + rows, err := s.db.Query("SELECT * FROM parcel WHERE client = :client", sql.Named("client", client)) + if err != nil { + return nil, err + } + defer rows.Close() // заполните срез Parcel данными из таблицы var res []Parcel + for rows.Next() { + p := Parcel{} + + err := rows.Scan(&p.Number, &p.Client, &p.Status, &p.Address, &p.CreatedAt) + if err != nil { + return nil, err + } + res = append(res, p) + } return res, nil } func (s ParcelStore) SetStatus(number int, status string) error { // реализуйте обновление статуса в таблице parcel + _, err := s.db.Exec("UPDATE parcel SET status = :status WHERE number = :number", + sql.Named("status", status), + sql.Named("number", number)) + if err != nil { + return err + } return nil } @@ -48,6 +84,21 @@ func (s ParcelStore) SetStatus(number int, status string) error { func (s ParcelStore) SetAddress(number int, address string) error { // реализуйте обновление адреса в таблице parcel // менять адрес можно только если значение статуса registered + var p string + row := s.db.QueryRow("SELECT status FROM parcel WHERE number = :number", sql.Named("number", number)) + err := row.Scan(&p) + if err != nil { + return err + } + + if p == ParcelStatusRegistered { + _, err := s.db.Exec("UPDATE parcel SET address = :address WHERE number = :number", + sql.Named("address", address), + sql.Named("number", number)) + if err != nil { + return err + } + } return nil } @@ -55,6 +106,19 @@ func (s ParcelStore) SetAddress(number int, address string) error { func (s ParcelStore) Delete(number int) error { // реализуйте удаление строки из таблицы parcel // удалять строку можно только если значение статуса registered + var p string + row := s.db.QueryRow("SELECT status FROM parcel WHERE number = :number", sql.Named("number", number)) + err := row.Scan(&p) + if err != nil { + return err + } + + if p == ParcelStatusRegistered { + _, err := s.db.Exec("DELETE FROM parcel WHERE number = :number", sql.Named("number", number)) + if err != nil { + return err + } + } return nil } diff --git a/parcel_test.go b/parcel_test.go index d1b93827..da21f9e4 100644 --- a/parcel_test.go +++ b/parcel_test.go @@ -7,6 +7,8 @@ import ( "time" "github.com/stretchr/testify/require" + + _ "modernc.org/sqlite" ) var ( @@ -31,57 +33,111 @@ func getTestParcel() Parcel { // TestAddGetDelete проверяет добавление, получение и удаление посылки func TestAddGetDelete(t *testing.T) { // prepare - db, err := // настройте подключение к БД + db, err := sql.Open("sqlite", "tracker.db") + if err != nil { + return + } + defer db.Close() + store := NewParcelStore(db) parcel := getTestParcel() // add // добавьте новую посылку в БД, убедитесь в отсутствии ошибки и наличии идентификатора + id, err := store.Add(parcel) + parcel.Number = int(id) + require.NoError(t, err) + require.NotEmpty(t, id) // get // получите только что добавленную посылку, убедитесь в отсутствии ошибки // проверьте, что значения всех полей в полученном объекте совпадают со значениями полей в переменной parcel + gettedParcel, err := store.Get(id) + require.NoError(t, err) + require.Equal(t, gettedParcel, parcel) // delete // удалите добавленную посылку, убедитесь в отсутствии ошибки // проверьте, что посылку больше нельзя получить из БД + err = store.Delete(id) + require.NoError(t, err) + + _, err = store.Get(id) + require.Equal(t, err, sql.ErrNoRows) } // TestSetAddress проверяет обновление адреса func TestSetAddress(t *testing.T) { // prepare - db, err := // настройте подключение к БД + db, err := sql.Open("sqlite", "tracker.db") + if err != nil { + return + } + defer db.Close() + + store := NewParcelStore(db) + parcel := getTestParcel() // add // добавьте новую посылку в БД, убедитесь в отсутствии ошибки и наличии идентификатора + id, err := store.Add(parcel) + require.NoError(t, err) + require.NotEmpty(t, id) // set address // обновите адрес, убедитесь в отсутствии ошибки newAddress := "new test address" + err = store.SetAddress(id, newAddress) + require.NoError(t, err) + // check // получите добавленную посылку и убедитесь, что адрес обновился + gettedParcel, err := store.Get(id) + require.NoError(t, err) + require.Equal(t, gettedParcel.Address, newAddress) } // TestSetStatus проверяет обновление статуса func TestSetStatus(t *testing.T) { // prepare - db, err := // настройте подключение к БД + db, err := sql.Open("sqlite", "tracker.db") + if err != nil { + return + } + defer db.Close() + + store := NewParcelStore(db) + parcel := getTestParcel() // add // добавьте новую посылку в БД, убедитесь в отсутствии ошибки и наличии идентификатора + id, err := store.Add(parcel) + require.NoError(t, err) + require.NotEmpty(t, id) // set status // обновите статус, убедитесь в отсутствии ошибки + err = store.SetStatus(id, ParcelStatusSent) + require.NoError(t, err) // check // получите добавленную посылку и убедитесь, что статус обновился + gettedParcel, err := store.Get(id) + require.NoError(t, err) + require.Equal(t, gettedParcel.Status, ParcelStatusSent) } // TestGetByClient проверяет получение посылок по идентификатору клиента func TestGetByClient(t *testing.T) { // prepare - db, err := // настройте подключение к БД + db, err := sql.Open("sqlite", "tracker.db") + if err != nil { + return + } + defer db.Close() + + store := NewParcelStore(db) parcels := []Parcel{ getTestParcel(), @@ -98,7 +154,10 @@ func TestGetByClient(t *testing.T) { // add for i := 0; i < len(parcels); i++ { - id, err := // добавьте новую посылку в БД, убедитесь в отсутствии ошибки и наличии идентификатора + // добавьте новую посылку в БД, убедитесь в отсутствии ошибки и наличии идентификатора + id, err := store.Add(parcels[i]) + require.NoError(t, err) + require.NotEmpty(t, id) // обновляем идентификатор добавленной у посылки parcels[i].Number = id @@ -108,14 +167,20 @@ func TestGetByClient(t *testing.T) { } // get by client - storedParcels, err := // получите список посылок по идентификатору клиента, сохранённого в переменной client + // получите список посылок по идентификатору клиента, сохранённого в переменной client // убедитесь в отсутствии ошибки // убедитесь, что количество полученных посылок совпадает с количеством добавленных + storedParcels, err := store.GetByClient(client) + require.NoError(t, err) + require.Equal(t, len(storedParcels), len(parcels)) // check for _, parcel := range storedParcels { // в parcelMap лежат добавленные посылки, ключ - идентификатор посылки, значение - сама посылка // убедитесь, что все посылки из storedParcels есть в parcelMap // убедитесь, что значения полей полученных посылок заполнены верно + _, ok :=parcelMap[parcel.Number] + require.True(t, ok) + require.Equal(t, parcel, parcelMap[parcel.Number]) } } diff --git a/tracker.db b/tracker.db index b6ba48a148daa7c8c4727d4bfc1c868229d7fb24..9afe743798fd473df18a2cc42051a984788cd8d6 100644 GIT binary patch delta 1349 zcmZp8z})bFd4e=!*hCp;)-VRWv{xHb7RhsbVc`G5e}n(VWB7DXn{*T|Y|&G=FzLe9iwzfB zFYLXr Date: Thu, 26 Jun 2025 18:45:49 +0300 Subject: [PATCH 2/3] second commit --- main.go | 10 +++---- parcel.go | 77 +++++++++++++++++++++++-------------------------- parcel_test.go | 51 ++++++++++++++++---------------- tracker.db | Bin 61440 -> 61440 bytes 4 files changed, 67 insertions(+), 71 deletions(-) diff --git a/main.go b/main.go index bcf1c66e..0a1f9578 100644 --- a/main.go +++ b/main.go @@ -98,11 +98,11 @@ 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() + if err != nil { + fmt.Println(err) + return + } + defer db.Close() // создайте объект ParcelStore функцией NewParcelStore store := NewParcelStore(db) diff --git a/parcel.go b/parcel.go index 0f562118..b8775cbf 100644 --- a/parcel.go +++ b/parcel.go @@ -20,28 +20,28 @@ func (s ParcelStore) Add(p Parcel) (int, error) { sql.Named("address", p.Address), sql.Named("created_at", p.CreatedAt)) if err != nil { - return 0, err - } + return 0, err + } // верните идентификатор последней добавленной записи id, err := res.LastInsertId() - if err != nil { - return 0, err - } + if err != nil { + return 0, err + } - return int(id), nil + return int(id), nil } func (s ParcelStore) Get(number int) (Parcel, error) { - p := Parcel{Number: number} + p := Parcel{} // реализуйте чтение строки по заданному number // здесь из таблицы должна вернуться только одна строка - row := s.db.QueryRow("SELECT client, status, address, created_at FROM parcel WHERE number = :number", sql.Named("number", p.Number)) + row := s.db.QueryRow("SELECT number, client, status, address, created_at FROM parcel WHERE number = :number", sql.Named("number", number)) // заполните объект Parcel данными из таблицы - err := row.Scan(&p.Client, &p.Status, &p.Address, &p.CreatedAt) + err := row.Scan(&p.Number, &p.Client, &p.Status, &p.Address, &p.CreatedAt) if err != nil { - return p, err - } + return Parcel{}, err + } return p, nil } @@ -49,22 +49,25 @@ func (s ParcelStore) GetByClient(client int) ([]Parcel, error) { // реализуйте чтение строк из таблицы parcel по заданному client // здесь из таблицы может вернуться несколько строк rows, err := s.db.Query("SELECT * FROM parcel WHERE client = :client", sql.Named("client", client)) - if err != nil { - return nil, err - } - defer rows.Close() + if err != nil { + return nil, err + } + defer rows.Close() // заполните срез Parcel данными из таблицы var res []Parcel for rows.Next() { - p := Parcel{} + p := Parcel{} - err := rows.Scan(&p.Number, &p.Client, &p.Status, &p.Address, &p.CreatedAt) - if err != nil { - return nil, err - } + err := rows.Scan(&p.Number, &p.Client, &p.Status, &p.Address, &p.CreatedAt) + if err != nil { + return nil, err + } res = append(res, p) } + //if err = rows.Err(); err != nil { + // return nil, err + //} return res, nil } @@ -75,8 +78,8 @@ func (s ParcelStore) SetStatus(number int, status string) error { sql.Named("status", status), sql.Named("number", number)) if err != nil { - return err - } + return err + } return nil } @@ -84,20 +87,12 @@ func (s ParcelStore) SetStatus(number int, status string) error { func (s ParcelStore) SetAddress(number int, address string) error { // реализуйте обновление адреса в таблице parcel // менять адрес можно только если значение статуса registered - var p string - row := s.db.QueryRow("SELECT status FROM parcel WHERE number = :number", sql.Named("number", number)) - err := row.Scan(&p) - if err != nil { - return err - } - - if p == ParcelStatusRegistered { - _, err := s.db.Exec("UPDATE parcel SET address = :address WHERE number = :number", - sql.Named("address", address), - sql.Named("number", number)) - if err != nil { - return err - } + _, err := s.db.Exec("UPDATE parcel SET address = :address WHERE number = :number AND status = :status", + sql.Named("address", address), + sql.Named("status", ParcelStatusRegistered), + sql.Named("number", number)) + if err != nil { + return err } return nil @@ -109,15 +104,15 @@ func (s ParcelStore) Delete(number int) error { var p string row := s.db.QueryRow("SELECT status FROM parcel WHERE number = :number", sql.Named("number", number)) err := row.Scan(&p) - if err != nil { - return err - } - + if err != nil { + return err + } + if p == ParcelStatusRegistered { _, err := s.db.Exec("DELETE FROM parcel WHERE number = :number", sql.Named("number", number)) if err != nil { return err - } + } } return nil diff --git a/parcel_test.go b/parcel_test.go index da21f9e4..528979f6 100644 --- a/parcel_test.go +++ b/parcel_test.go @@ -7,7 +7,8 @@ import ( "time" "github.com/stretchr/testify/require" - + "github.com/stretchr/testify/assert" + _ "modernc.org/sqlite" ) @@ -34,10 +35,10 @@ func getTestParcel() Parcel { func TestAddGetDelete(t *testing.T) { // prepare db, err := sql.Open("sqlite", "tracker.db") - if err != nil { - return - } - defer db.Close() + if err != nil { + return + } + defer db.Close() store := NewParcelStore(db) parcel := getTestParcel() @@ -70,10 +71,10 @@ func TestAddGetDelete(t *testing.T) { func TestSetAddress(t *testing.T) { // prepare db, err := sql.Open("sqlite", "tracker.db") - if err != nil { - return - } - defer db.Close() + if err != nil { + return + } + defer db.Close() store := NewParcelStore(db) parcel := getTestParcel() @@ -102,10 +103,10 @@ func TestSetAddress(t *testing.T) { func TestSetStatus(t *testing.T) { // prepare db, err := sql.Open("sqlite", "tracker.db") - if err != nil { - return - } - defer db.Close() + if err != nil { + return + } + defer db.Close() store := NewParcelStore(db) parcel := getTestParcel() @@ -124,18 +125,18 @@ func TestSetStatus(t *testing.T) { // check // получите добавленную посылку и убедитесь, что статус обновился gettedParcel, err := store.Get(id) - require.NoError(t, err) - require.Equal(t, gettedParcel.Status, ParcelStatusSent) + assert.NoError(t, err) + assert.Equal(t, gettedParcel.Status, ParcelStatusSent) } // TestGetByClient проверяет получение посылок по идентификатору клиента func TestGetByClient(t *testing.T) { // prepare db, err := sql.Open("sqlite", "tracker.db") - if err != nil { - return - } - defer db.Close() + if err != nil { + return + } + defer db.Close() store := NewParcelStore(db) @@ -157,7 +158,7 @@ func TestGetByClient(t *testing.T) { // добавьте новую посылку в БД, убедитесь в отсутствии ошибки и наличии идентификатора id, err := store.Add(parcels[i]) require.NoError(t, err) - require.NotEmpty(t, id) + require.NotEmpty(t, id) // обновляем идентификатор добавленной у посылки parcels[i].Number = id @@ -171,16 +172,16 @@ func TestGetByClient(t *testing.T) { // убедитесь в отсутствии ошибки // убедитесь, что количество полученных посылок совпадает с количеством добавленных storedParcels, err := store.GetByClient(client) - require.NoError(t, err) - require.Equal(t, len(storedParcels), len(parcels)) + assert.NoError(t, err) + assert.Len(t, storedParcels, len(parcels)) // check for _, parcel := range storedParcels { // в parcelMap лежат добавленные посылки, ключ - идентификатор посылки, значение - сама посылка // убедитесь, что все посылки из storedParcels есть в parcelMap // убедитесь, что значения полей полученных посылок заполнены верно - _, ok :=parcelMap[parcel.Number] - require.True(t, ok) - require.Equal(t, parcel, parcelMap[parcel.Number]) + testParcel, ok := parcelMap[parcel.Number] + assert.True(t, ok) + assert.Equal(t, parcel, testParcel) } } diff --git a/tracker.db b/tracker.db index 9afe743798fd473df18a2cc42051a984788cd8d6..6b88617db6e0d0ab519dcc3eb9964d5e04156936 100644 GIT binary patch delta 653 zcmZp8z})bFd4e=!)kGO*#;T18^Yu9lc^McOv{_G0W;ZZY)FcL0@+kpzq6j&*qFo0t!>E0z^o{0>eZ(?xxr3E(oEOLEX2^% z%EZ{p*gQ(x0I#e*imU*tUKPE`6KuuM1kH3OU$oIc6U@+>tY;skh@{=nBq~pnoq*2lI00L(<{9 delta 41 xcmZp8z})bFd4e=!*hCp;#;}bE^YuAoco`TNB)F|6vl|$0Y-HlzY-N3H3jhf=3|RmG From 6e41c80a69b9054519b1678901cbe9164ba47b2d Mon Sep 17 00:00:00 2001 From: mixa4045 Date: Tue, 1 Jul 2025 17:41:35 +0300 Subject: [PATCH 3/3] third commit --- parcel.go | 19 ++++++------------- parcel_test.go | 20 ++++++-------------- tracker.db | Bin 61440 -> 61440 bytes 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/parcel.go b/parcel.go index b8775cbf..ce3ba800 100644 --- a/parcel.go +++ b/parcel.go @@ -65,9 +65,9 @@ func (s ParcelStore) GetByClient(client int) ([]Parcel, error) { } res = append(res, p) } - //if err = rows.Err(); err != nil { - // return nil, err - //} + if err = rows.Err(); err != nil { + return nil, err + } return res, nil } @@ -101,19 +101,12 @@ func (s ParcelStore) SetAddress(number int, address string) error { func (s ParcelStore) Delete(number int) error { // реализуйте удаление строки из таблицы parcel // удалять строку можно только если значение статуса registered - var p string - row := s.db.QueryRow("SELECT status FROM parcel WHERE number = :number", sql.Named("number", number)) - err := row.Scan(&p) - if err != nil { - return err - } - - if p == ParcelStatusRegistered { - _, err := s.db.Exec("DELETE FROM parcel WHERE number = :number", sql.Named("number", number)) + _, err := s.db.Exec("DELETE FROM parcel WHERE number = :number AND status = :status", + sql.Named("status", ParcelStatusRegistered), + sql.Named("number", number)) if err != nil { return err } - } return nil } diff --git a/parcel_test.go b/parcel_test.go index 528979f6..d0ab368f 100644 --- a/parcel_test.go +++ b/parcel_test.go @@ -35,9 +35,7 @@ func getTestParcel() Parcel { func TestAddGetDelete(t *testing.T) { // prepare db, err := sql.Open("sqlite", "tracker.db") - if err != nil { - return - } + require.NoError(t, err) defer db.Close() store := NewParcelStore(db) @@ -71,9 +69,7 @@ func TestAddGetDelete(t *testing.T) { func TestSetAddress(t *testing.T) { // prepare db, err := sql.Open("sqlite", "tracker.db") - if err != nil { - return - } + require.NoError(t, err) defer db.Close() store := NewParcelStore(db) @@ -103,9 +99,7 @@ func TestSetAddress(t *testing.T) { func TestSetStatus(t *testing.T) { // prepare db, err := sql.Open("sqlite", "tracker.db") - if err != nil { - return - } + require.NoError(t, err) defer db.Close() store := NewParcelStore(db) @@ -125,7 +119,7 @@ func TestSetStatus(t *testing.T) { // check // получите добавленную посылку и убедитесь, что статус обновился gettedParcel, err := store.Get(id) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, gettedParcel.Status, ParcelStatusSent) } @@ -133,9 +127,7 @@ func TestSetStatus(t *testing.T) { func TestGetByClient(t *testing.T) { // prepare db, err := sql.Open("sqlite", "tracker.db") - if err != nil { - return - } + require.NoError(t, err) defer db.Close() store := NewParcelStore(db) @@ -172,7 +164,7 @@ func TestGetByClient(t *testing.T) { // убедитесь в отсутствии ошибки // убедитесь, что количество полученных посылок совпадает с количеством добавленных storedParcels, err := store.GetByClient(client) - assert.NoError(t, err) + require.NoError(t, err) assert.Len(t, storedParcels, len(parcels)) // check diff --git a/tracker.db b/tracker.db index 6b88617db6e0d0ab519dcc3eb9964d5e04156936..cc35ea7f6655e41c8849485c9ceeb32fe2cf1def 100644 GIT binary patch delta 208 zcmZp8z})bFd4e=!$3z)t#*U2%^Yu9_c^McO3|Xotvm1o-uqLo-urje+Wm&;ey|Gb{ zgIE&w4z4c!0$