package link import ( "context" "errors" "github.com/jackc/pgtype" "github.com/jackc/pgx/v4" "github.com/jackc/pgx/v4/pgxpool" "net/url" ) type Repository interface { Save(link *Link) error FindById(id string) (*Link, error) DeleteById(id string) error } type PgRepository struct { pool *pgxpool.Pool } func (r *PgRepository) Save(link *Link) error { ctx := context.Background() tx, err := r.pool.Begin(ctx) if err != nil { return err } sql := ` INSERT INTO links (id, name, redirect_url, creation_time) VALUES ($1, $2, $3, $4::timestamp) ` _, err = tx.Exec(ctx, sql, link.Id, link.Name, link.RedirectURL.String(), link.CreationTime.Format("2006-01-02 15:04:05")) if err != nil { _ = tx.Rollback(ctx) return err } if err = tx.Commit(ctx); err != nil { return err } return nil } func (r *PgRepository) FindById(id string) (*Link, error) { ctx := context.Background() tx, err := r.pool.Begin(ctx) if err != nil { return nil, err } sql := ` SELECT id, name, redirect_url, creation_time FROM links WHERE id = $1 ` entity, err := mapRowToEntity(tx.QueryRow(ctx, sql, id)) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return nil, nil } else { _ = tx.Rollback(ctx) return nil, err } } if err = tx.Commit(ctx); err != nil { return nil, err } return entity, nil } func (r *PgRepository) DeleteById(id string) error { ctx := context.Background() tx, err := r.pool.Begin(ctx) if err != nil { return err } sql := ` DELETE FROM links WHERE id = $1 ` _, err = tx.Exec(ctx, sql, id) if err != nil { _ = tx.Rollback(ctx) return err } if err = tx.Commit(ctx); err != nil { return err } return nil } func mapRowToEntity(r pgx.Row) (*Link, error) { var entity Link var urlStr string var t pgtype.Timestamp if err := r.Scan(&entity.Id, &entity.Name, &urlStr, &t); err != nil { return nil, err } u, err := url.Parse(urlStr) if err != nil { return nil, err } entity.RedirectURL = *u entity.CreationTime = t.Time return &entity, nil }