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