feat: implemented many commands
- added register command - added reset command - added users command - added agg command - added feeds command
This commit is contained in:
@@ -1,3 +1,8 @@
|
|||||||
module github.com/StevanFreeborn/gator
|
module github.com/StevanFreeborn/gator
|
||||||
|
|
||||||
go 1.26.3
|
go 1.26.3
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/lib/pq v1.12.3 // indirect
|
||||||
|
)
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
|
||||||
|
github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
|
||||||
+193
-1
@@ -1,9 +1,18 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/StevanFreeborn/gator/internal/database"
|
||||||
|
"github.com/StevanFreeborn/gator/internal/rss"
|
||||||
"github.com/StevanFreeborn/gator/internal/state"
|
"github.com/StevanFreeborn/gator/internal/state"
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Command struct {
|
type Command struct {
|
||||||
@@ -36,6 +45,12 @@ func NewRegistry() *CommandRegistry {
|
|||||||
|
|
||||||
commands := []*Command{
|
commands := []*Command{
|
||||||
loginCommand(),
|
loginCommand(),
|
||||||
|
registerCommand(),
|
||||||
|
resetCommand(),
|
||||||
|
usersCommand(),
|
||||||
|
aggCommand(),
|
||||||
|
addFeedCommand(),
|
||||||
|
feedsCommand(),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cmd := range commands {
|
for _, cmd := range commands {
|
||||||
@@ -63,7 +78,13 @@ func loginCommand() *Command {
|
|||||||
|
|
||||||
username := s.Arguments[0]
|
username := s.Arguments[0]
|
||||||
|
|
||||||
err := s.Config.SetUser(username)
|
_, err := s.Database.GetUserByName(context.Background(), username)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to login")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.Config.SetUser(username)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -74,3 +95,174 @@ func loginCommand() *Command {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func registerCommand() *Command {
|
||||||
|
return newCommand("register", func(s *state.State) error {
|
||||||
|
if len(s.Arguments) == 0 {
|
||||||
|
return fmt.Errorf("Did not receive expected username argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
createUserParams := database.CreateUserParams{
|
||||||
|
ID: uuid.New(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
UpdatedAt: time.Now(),
|
||||||
|
Name: s.Arguments[0],
|
||||||
|
}
|
||||||
|
|
||||||
|
createdUser, err := s.Database.CreateUser(context.Background(), createUserParams)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Config.SetUser(createdUser.Name)
|
||||||
|
|
||||||
|
fmt.Printf("Successfully registered user '%s':\n", createdUser.Name)
|
||||||
|
fmt.Printf(" Id => %s\n", createdUser.ID)
|
||||||
|
fmt.Printf(" CreatedAt => %s\n", createdUser.CreatedAt)
|
||||||
|
fmt.Printf(" UpdatedAt => %s\n", createdUser.UpdatedAt)
|
||||||
|
fmt.Printf("Current user set to user '%s':\n", createdUser.Name)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetCommand() *Command {
|
||||||
|
return newCommand("reset", func(s *state.State) error {
|
||||||
|
err := s.Database.DeleteAllUsers(context.Background())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Successfully delete all users")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func usersCommand() *Command {
|
||||||
|
return newCommand("users", func(s *state.State) error {
|
||||||
|
users, err := s.Database.GetAllUsers(context.Background())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
slices.SortFunc(users, func(a, b database.User) int {
|
||||||
|
return cmp.Compare(a.Name, b.Name)
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
msg := "* %s"
|
||||||
|
|
||||||
|
if user.Name == s.Config.CurrentUserName {
|
||||||
|
msg += " (current)"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(msg+"\n", user.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func aggCommand() *Command {
|
||||||
|
return newCommand("agg", func(s *state.State) error {
|
||||||
|
// if len(s.Arguments) == 0 {
|
||||||
|
// return fmt.Errorf("Did not receive expected feed argument")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// feed := s.Arguments[0]
|
||||||
|
//
|
||||||
|
// validUrl, err := url.Parse(feed)
|
||||||
|
//
|
||||||
|
// if err != nil {
|
||||||
|
// return fmt.Errorf("Feed '%s' is not a valid url", feed)
|
||||||
|
// }
|
||||||
|
|
||||||
|
rssFeed, err := rss.FetchFeed(context.Background(), "https://www.wagslane.dev/index.xml")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%v\n", rssFeed)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFeedCommand() *Command {
|
||||||
|
return newCommand("addfeed", func(s *state.State) error {
|
||||||
|
if len(s.Arguments) < 2 {
|
||||||
|
return fmt.Errorf("Did not receive expected feed name and url")
|
||||||
|
}
|
||||||
|
|
||||||
|
feedName := s.Arguments[0]
|
||||||
|
feedUrl := s.Arguments[1]
|
||||||
|
|
||||||
|
validatedFeedUrl, err := url.Parse(feedUrl)
|
||||||
|
|
||||||
|
if strings.TrimSpace(feedName) == "" {
|
||||||
|
return fmt.Errorf("Feed name cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Feed url '%s' is not a valid url", feedUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentUser, err := s.GetCurrentUser(context.Background())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Currently logged in user does not exist. Cannot add feed for non-existent user.")
|
||||||
|
}
|
||||||
|
|
||||||
|
createFeedParams := database.CreateFeedParams{
|
||||||
|
ID: uuid.New(),
|
||||||
|
UserID: currentUser.ID,
|
||||||
|
Name: feedName,
|
||||||
|
Url: validatedFeedUrl.String(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
UpdatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
createdFeed, err := s.Database.CreateFeed(context.Background(), createFeedParams)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Successfully added feed '%s' with url '%s'\n", createdFeed.Name, createdFeed.Url)
|
||||||
|
fmt.Printf(" Id => %s\n", createdFeed.ID)
|
||||||
|
fmt.Printf(" UserId => %s\n", createdFeed.UserID)
|
||||||
|
fmt.Printf(" CreatedAt => %s\n", createdFeed.CreatedAt)
|
||||||
|
fmt.Printf(" UpdatedAt => %s\n", createdFeed.UpdatedAt)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func feedsCommand() *Command {
|
||||||
|
return newCommand("feeds", func(s *state.State) error {
|
||||||
|
feeds, err := s.Database.GetAllFeeds(context.Background())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, feed := range feeds {
|
||||||
|
feedsUserName := "Unknown"
|
||||||
|
|
||||||
|
user, err := s.Database.GetUserById(context.Background(), feed.UserID)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
feedsUserName = user.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("* %s [%s] (%s)\n", feed.Name, feed.Url, feedsUserName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DBTX interface {
|
||||||
|
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
|
||||||
|
PrepareContext(context.Context, string) (*sql.Stmt, error)
|
||||||
|
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
|
||||||
|
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(db DBTX) *Queries {
|
||||||
|
return &Queries{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Queries struct {
|
||||||
|
db DBTX
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
||||||
|
return &Queries{
|
||||||
|
db: tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
// source: feeds.sql
|
||||||
|
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
const createFeed = `-- name: CreateFeed :one
|
||||||
|
INSERT INTO feeds (id, created_at, updated_at, name, url, user_id)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6
|
||||||
|
)
|
||||||
|
RETURNING id, created_at, updated_at, name, url, user_id
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateFeedParams struct {
|
||||||
|
ID uuid.UUID
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
Name string
|
||||||
|
Url string
|
||||||
|
UserID uuid.UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateFeed(ctx context.Context, arg CreateFeedParams) (Feed, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, createFeed,
|
||||||
|
arg.ID,
|
||||||
|
arg.CreatedAt,
|
||||||
|
arg.UpdatedAt,
|
||||||
|
arg.Name,
|
||||||
|
arg.Url,
|
||||||
|
arg.UserID,
|
||||||
|
)
|
||||||
|
var i Feed
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.Name,
|
||||||
|
&i.Url,
|
||||||
|
&i.UserID,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getAllFeeds = `-- name: GetAllFeeds :many
|
||||||
|
SELECT id, created_at, updated_at, name, url, user_id FROM feeds
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetAllFeeds(ctx context.Context) ([]Feed, error) {
|
||||||
|
rows, err := q.db.QueryContext(ctx, getAllFeeds)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []Feed
|
||||||
|
for rows.Next() {
|
||||||
|
var i Feed
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.Name,
|
||||||
|
&i.Url,
|
||||||
|
&i.UserID,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Feed struct {
|
||||||
|
ID uuid.UUID
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
Name string
|
||||||
|
Url string
|
||||||
|
UserID uuid.UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID uuid.UUID
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
Name string
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
// source: users.sql
|
||||||
|
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
const createUser = `-- name: CreateUser :one
|
||||||
|
INSERT INTO users (id, created_at, updated_at, name)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4
|
||||||
|
)
|
||||||
|
RETURNING id, created_at, updated_at, name
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateUserParams struct {
|
||||||
|
ID uuid.UUID
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, createUser,
|
||||||
|
arg.ID,
|
||||||
|
arg.CreatedAt,
|
||||||
|
arg.UpdatedAt,
|
||||||
|
arg.Name,
|
||||||
|
)
|
||||||
|
var i User
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.Name,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteAllUsers = `-- name: DeleteAllUsers :exec
|
||||||
|
DELETE FROM users
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteAllUsers(ctx context.Context) error {
|
||||||
|
_, err := q.db.ExecContext(ctx, deleteAllUsers)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getAllUsers = `-- name: GetAllUsers :many
|
||||||
|
SELECT id, created_at, updated_at, name FROM users
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetAllUsers(ctx context.Context) ([]User, error) {
|
||||||
|
rows, err := q.db.QueryContext(ctx, getAllUsers)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []User
|
||||||
|
for rows.Next() {
|
||||||
|
var i User
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.Name,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUserById = `-- name: GetUserById :one
|
||||||
|
SELECT id, created_at, updated_at, name FROM users
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetUserById(ctx context.Context, id uuid.UUID) (User, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, getUserById, id)
|
||||||
|
var i User
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.Name,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUserByName = `-- name: GetUserByName :one
|
||||||
|
SELECT id, created_at, updated_at, name FROM users
|
||||||
|
WHERE name = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetUserByName(ctx context.Context, name string) (User, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, getUserByName, name)
|
||||||
|
var i User
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.Name,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package rss
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/xml"
|
||||||
|
"html"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RSSItem struct {
|
||||||
|
Title string `xml:"title"`
|
||||||
|
Link string `xml:"link"`
|
||||||
|
Description string `xml:"description"`
|
||||||
|
PubDate string `xml:"pubDate"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RSSChannel struct {
|
||||||
|
Title string `xml:"title"`
|
||||||
|
Link string `xml:"link"`
|
||||||
|
Description string `xml:"description"`
|
||||||
|
Item []RSSItem `xml:"item"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RSSFeed struct {
|
||||||
|
Channel RSSChannel `xml:"channel"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func FetchFeed(ctx context.Context, feedURL string) (*RSSFeed, error) {
|
||||||
|
var rssFeed RSSFeed
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, feedURL, nil)
|
||||||
|
req.Header.Set("User-Agent", "gator")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := http.DefaultClient.Do(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
err = xml.NewDecoder(res.Body).Decode(&rssFeed)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rssFeed.Channel.Title = html.UnescapeString(rssFeed.Channel.Title)
|
||||||
|
rssFeed.Channel.Description = html.UnescapeString(rssFeed.Channel.Description)
|
||||||
|
|
||||||
|
for _, item := range rssFeed.Channel.Item {
|
||||||
|
item.Title = html.UnescapeString(item.Title)
|
||||||
|
item.Description = html.UnescapeString(item.Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &rssFeed, nil
|
||||||
|
}
|
||||||
+13
-3
@@ -1,12 +1,22 @@
|
|||||||
package state
|
package state
|
||||||
|
|
||||||
import "github.com/StevanFreeborn/gator/internal/config"
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/StevanFreeborn/gator/internal/config"
|
||||||
|
"github.com/StevanFreeborn/gator/internal/database"
|
||||||
|
)
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
|
Database *database.Queries
|
||||||
Config *config.Config
|
Config *config.Config
|
||||||
Arguments []string
|
Arguments []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewState(c *config.Config, args []string) *State {
|
func NewState(d *database.Queries, c *config.Config, args []string) *State {
|
||||||
return &State{Config: c, Arguments: args}
|
return &State{Database: d, Config: c, Arguments: args}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *State) GetCurrentUser(ctx context.Context) (database.User, error) {
|
||||||
|
return s.Database.GetUserByName(ctx, s.Config.CurrentUserName)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/StevanFreeborn/gator/internal/command"
|
"github.com/StevanFreeborn/gator/internal/command"
|
||||||
"github.com/StevanFreeborn/gator/internal/config"
|
"github.com/StevanFreeborn/gator/internal/config"
|
||||||
|
"github.com/StevanFreeborn/gator/internal/database"
|
||||||
"github.com/StevanFreeborn/gator/internal/state"
|
"github.com/StevanFreeborn/gator/internal/state"
|
||||||
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -19,19 +22,28 @@ func main() {
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error reading config file: %s", err)
|
fmt.Printf("Error reading config file: %s", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := sql.Open("postgres", c.DbUrl)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error connecting to database: %s", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := os.Args[1]
|
cmd := os.Args[1]
|
||||||
args := os.Args[2:]
|
args := os.Args[2:]
|
||||||
|
|
||||||
s := state.NewState(c, args)
|
dbQueries := database.New(db)
|
||||||
|
s := state.NewState(dbQueries, c, args)
|
||||||
|
|
||||||
registry := command.NewRegistry()
|
registry := command.NewRegistry()
|
||||||
err = registry.RunCommand(cmd, s)
|
err = registry.RunCommand(cmd, s)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error running '%s' command: %s\n", cmd, err)
|
fmt.Printf("Error running '%s' command: %s\n", cmd, err)
|
||||||
os.Exit(2)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
-- name: CreateFeed :one
|
||||||
|
INSERT INTO feeds (id, created_at, updated_at, name, url, user_id)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6
|
||||||
|
)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetAllFeeds :many
|
||||||
|
SELECT id, created_at, updated_at, name, url, user_id FROM feeds;
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
-- name: CreateUser :one
|
||||||
|
INSERT INTO users (id, created_at, updated_at, name)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4
|
||||||
|
)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetUserByName :one
|
||||||
|
SELECT id, created_at, updated_at, name FROM users
|
||||||
|
WHERE name = $1;
|
||||||
|
|
||||||
|
-- name: GetUserById :one
|
||||||
|
SELECT id, created_at, updated_at, name FROM users
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: GetAllUsers :many
|
||||||
|
SELECT id, created_at, updated_at, name FROM users;
|
||||||
|
|
||||||
|
-- name: DeleteAllUsers :exec
|
||||||
|
DELETE FROM users;
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
-- +goose Up
|
||||||
|
CREATE TABLE feeds (
|
||||||
|
id UUID PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL,
|
||||||
|
updated_at TIMESTAMP NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
url TEXT UNIQUE NOT NULL,
|
||||||
|
user_id UUID NOT NULL,
|
||||||
|
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE feeds;
|
||||||
Reference in New Issue
Block a user