url_shortener/internal/storage/sqlite/sqlite.go

81 lines
1.6 KiB
Go

package sqlite
import (
"database/sql"
"errors"
"fmt"
"url-shortener/internal/storage"
"github.com/mattn/go-sqlite3"
)
type Storage struct {
db *sql.DB
}
func New(storagePath string) (*Storage, error) {
const op = "storage.sqlite.New"
db, err := sql.Open("sqlite3", storagePath)
if err != nil {
return nil, fmt.Errorf("%s: %w", op, err)
}
// TODO: migrations
_, err = db.Exec(`
CREATE TABLE IF NOT EXISTS url(
id INTEGER PRIMARY KEY,
alias TEXT NOT NULL UNIQUE,
url TEXT NOT NULL);
CREATE INDEX IF NOT EXISTS idx_alias ON url(alias);`)
if err != nil {
return nil, fmt.Errorf("%s: %w", op, err)
}
return &Storage{db: db}, nil
}
func (s *Storage) SaveURL(urlToSave string, alias string) error {
const op = "storage.sqlite.SaveURL"
stmt, err := s.db.Prepare("INSERT INTO url (url, alias) values (?, ?)")
if err != nil {
return fmt.Errorf("%s: %w", op, err)
}
_, err = stmt.Exec(urlToSave, alias)
if err != nil {
if sqliteErr, ok := err.(sqlite3.Error); ok && sqliteErr.ExtendedCode == sqlite3.ErrConstraintUnique {
return storage.ErrURLExists
}
return fmt.Errorf("%s: %w", op, err)
}
return nil
}
func (s *Storage) GetURL(alias string) (string, error) {
const op = "storage.sqlite.GetURL"
stmt, err := s.db.Prepare("SELECT url from url where alias = ?")
if err != nil {
return "", fmt.Errorf("%s: %w", op, err)
}
var resURL string
err = stmt.QueryRow(alias).Scan(&resURL)
if errors.Is(err, sql.ErrNoRows) {
return "", storage.ErrURLNotFound
}
if err != nil {
return "", fmt.Errorf("%s: %w", op, err)
}
return resURL, nil
}
// TODO: Implement method
// func (s *Storage) DeleteURL(alias string) error