HUGE progress

This commit is contained in:
Jakub Kropáček 2024-11-17 00:54:15 +01:00
parent a9623fa7be
commit c3610ac1e4
10 changed files with 265 additions and 58 deletions

4
.gitignore vendored
View file

@ -1,2 +1,2 @@
secret-santa
*.db
*.db
.idea/

31
cmd/secret-santa/main.go Normal file
View file

@ -0,0 +1,31 @@
package main
import (
"database/sql"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/app"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/config"
"log"
"net/http"
_ "github.com/mattn/go-sqlite3"
)
func main() {
dbConnection, err := sql.Open("sqlite3", "./test.db")
if err != nil {
log.Fatal(err)
}
log.Println("Database sucessfully connected")
appConfig := config.NewAppConfig(nil, nil)
application := app.NewApp(dbConnection, &appConfig)
log.Printf("Listening on http://%s", appConfig.GenerateIP())
log.Fatal(
http.ListenAndServe(
appConfig.GenerateIP(),
application.Router(),
),
)
}

32
internal/app/app.go Normal file
View file

@ -0,0 +1,32 @@
package app
import (
"database/sql"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/config"
"net/http"
)
type App struct {
Config config.AppConfig
DB *sql.DB
}
func NewApp(db *sql.DB, appConfig *config.AppConfig) *App {
defaultConfig := config.NewAppConfig(nil, nil)
if appConfig == nil {
appConfig = &defaultConfig
}
return &App{
Config: *appConfig,
DB: db,
}
}
func (a *App) Router() http.Handler {
router := http.NewServeMux()
AddRoutes(router, a.DB)
return router
}

14
internal/app/routes.go Normal file
View file

@ -0,0 +1,14 @@
package app
import (
"database/sql"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/handlers"
"net/http"
)
func AddRoutes(router *http.ServeMux, db *sql.DB) {
router.HandleFunc("GET /users/{id}", handlers.HandleGetUsersByID(db))
router.HandleFunc("GET /users/", handlers.HandleGetUsers(db))
router.HandleFunc("POST /users/", handlers.HandleCreateUser(db))
router.HandleFunc("DELETE /users/{id}", handlers.HandleDeleteUser(db))
}

29
internal/config/config.go Normal file
View file

@ -0,0 +1,29 @@
package config
import "fmt"
type AppConfig struct {
ListenIP string `json:"listen_ip"`
ListenPort int `json:"listen_port"`
}
func (c *AppConfig) GenerateIP() string {
return fmt.Sprintf("%s:%d", c.ListenIP, c.ListenPort)
}
func NewAppConfig(port *int, ip *string) AppConfig {
defaultPort := 8080
defaultIp := "127.0.0.1"
if port == nil {
port = &defaultPort
}
if ip == nil {
ip = &defaultIp
}
return AppConfig{
ListenIP: *ip,
ListenPort: *port,
}
}

View file

@ -0,0 +1,93 @@
package handlers
import (
"context"
"database/sql"
"errors"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/queries"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/types"
"net/http"
)
func HandleGetUsers(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := context.Background()
query := queries.New(db)
users, err := query.GetUsers(ctx)
if err != nil {
writeErrorResponse(w, 500, err.Error())
return
}
if len(users) == 0 {
users = []queries.User{}
}
writeJSONResponse(w, 200, types.JsonResponse[[]queries.User]{Data: users})
}
}
func HandleGetUsersByID(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := context.Background()
query := queries.New(db)
id, err := parseIDFromURL(r)
if err != nil {
writeErrorResponse(w, 500, err.Error())
return
}
user, err := query.GetUserId(ctx, id)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
writeErrorResponse(w, 404, "User not found")
return
}
writeErrorResponse(w, 500, err.Error())
return
}
writeJSONResponse(w, 200, types.JsonResponse[queries.User]{Data: user})
}
}
func HandleCreateUser(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := context.Background()
query := queries.New(db)
var createUser queries.CreateUserParams
err := readJSONRequest(r, &createUser)
if err != nil {
writeErrorResponse(w, 500, err.Error())
return
}
user, err := query.CreateUser(ctx, createUser)
if err != nil {
writeErrorResponse(w, 500, err.Error())
return
}
writeJSONResponse(w, 201, types.JsonResponse[queries.User]{Data: user})
}
}
func HandleDeleteUser(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := context.Background()
query := queries.New(db)
id, err := parseIDFromURL(r)
if err != nil {
writeErrorResponse(w, 500, err.Error())
return
}
err = query.DeleteUser(ctx, id)
if err != nil {
writeErrorResponse(w, 500, err.Error())
return
}
writeJSONResponse(w, 204, nil)
}
}

View file

@ -0,0 +1,38 @@
package handlers
import (
"encoding/json"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/types"
"log"
"net/http"
"strconv"
)
func writeJSONResponse(w http.ResponseWriter, statusCode int, data interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(statusCode)
err := json.NewEncoder(w).Encode(data)
if err != nil {
log.Fatalf("Failed to write response. Error: %s\n", err)
}
}
func writeErrorResponse(w http.ResponseWriter, statusCode int, message string) {
writeJSONResponse(w, statusCode, types.ErrorResponse{Message: message})
}
func readJSONRequest(r *http.Request, data interface{}) error {
err := json.NewDecoder(r.Body).Decode(data)
if err != nil {
return err
}
return nil
}
func parseIDFromURL(r *http.Request) (int64, error) {
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err != nil {
return 0, err
}
return id, nil
}

View file

@ -9,8 +9,9 @@ import (
"context"
)
const createUser = `-- name: CreateUser :exec
const createUser = `-- name: CreateUser :one
INSERT INTO users (id, email, first_name, last_name) VALUES (NULL, ?, ?, ?)
RETURNING id, first_name, last_name, email
`
type CreateUserParams struct {
@ -19,8 +20,24 @@ type CreateUserParams struct {
LastName string `json:"last_name"`
}
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) error {
_, err := q.db.ExecContext(ctx, createUser, arg.Email, arg.FirstName, arg.LastName)
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) {
row := q.db.QueryRowContext(ctx, createUser, arg.Email, arg.FirstName, arg.LastName)
var i User
err := row.Scan(
&i.ID,
&i.FirstName,
&i.LastName,
&i.Email,
)
return i, err
}
const deleteUser = `-- name: DeleteUser :exec
DELETE FROM users WHERE id = ?
`
func (q *Queries) DeleteUser(ctx context.Context, id int64) error {
_, err := q.db.ExecContext(ctx, deleteUser, id)
return err
}

51
main.go
View file

@ -1,51 +0,0 @@
package main
import (
"context"
"database/sql"
"encoding/json"
"log"
"net/http"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/queries"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/types"
_ "github.com/mattn/go-sqlite3"
)
var dbConnection *sql.DB
func init() {
var err error
dbConnection, err = sql.Open("sqlite3", "./test.db")
if err != nil {
log.Fatal(err)
}
log.Println("Database sucessfully connected")
}
func main() {
ctx := context.Background()
log.Println("Created database connection")
router := http.NewServeMux()
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
query := queries.New(dbConnection)
w.Header().Set("Content-Type", "application/json")
users, err := query.GetUsers(ctx)
if err != nil {
w.WriteHeader(404)
log.Printf("Failed to get all users: %s\n", err.Error())
json.NewEncoder(w).Encode(types.ErrorResponse{Message: err.Error()})
return
}
if len(users) == 0 {
users = make([]queries.User, 0)
}
json.NewEncoder(w).Encode(types.JsonResponse[[]queries.User]{Data: users})
})
log.Fatal(http.ListenAndServe(":8080", router))
}

View file

@ -5,5 +5,9 @@ WHERE id = ? LIMIT 1;
-- name: GetUsers :many
SELECT * FROM users;
-- name: CreateUser :exec
INSERT INTO users (id, email, first_name, last_name) VALUES (NULL, ?, ?, ?);
-- name: CreateUser :one
INSERT INTO users (id, email, first_name, last_name) VALUES (NULL, ?, ?, ?)
RETURNING *;
-- name: DeleteUser :exec
DELETE FROM users WHERE id = ?;