81 lines
1.6 KiB
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
|