lot of breaking changes, checking in before stepping away
This commit is contained in:
@@ -20,9 +20,33 @@ const (
|
|||||||
Other
|
Other
|
||||||
)
|
)
|
||||||
|
|
||||||
// entities
|
var CategoryMap = map[Category]string{
|
||||||
type Item struct {
|
Bedroom: "Bedroom",
|
||||||
|
Bathroom: "Bathroom",
|
||||||
|
Kitchen: "Kitchen",
|
||||||
|
Office: "Office",
|
||||||
|
LivingRoom: "Living Room",
|
||||||
|
Other: "Other",
|
||||||
|
}
|
||||||
|
|
||||||
|
var PackingStageMap = map[PackingStage]string{
|
||||||
|
Essentials: "Essentials",
|
||||||
|
StageOne: "Stage One",
|
||||||
|
StageTwo: "Stage Two",
|
||||||
|
StageThree: "Stage Three",
|
||||||
|
}
|
||||||
|
|
||||||
|
type EntityLabel string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ItemType EntityLabel = "items"
|
||||||
|
BoxType EntityLabel = "boxes"
|
||||||
|
BoxItemType EntityLabel = "box_items"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Entity struct {
|
||||||
ID int
|
ID int
|
||||||
|
EntityLabel EntityLabel
|
||||||
Name string
|
Name string
|
||||||
Notes *string
|
Notes *string
|
||||||
Description *string
|
Description *string
|
||||||
@@ -30,14 +54,8 @@ type Item struct {
|
|||||||
Category Category
|
Category Category
|
||||||
}
|
}
|
||||||
|
|
||||||
type Box struct {
|
type Item Entity
|
||||||
ID int
|
type Box Entity
|
||||||
Name string
|
|
||||||
Notes *string
|
|
||||||
Description *string
|
|
||||||
Stage PackingStage
|
|
||||||
Category Category
|
|
||||||
}
|
|
||||||
|
|
||||||
// joins
|
// joins
|
||||||
type BoxItem struct {
|
type BoxItem struct {
|
||||||
|
|||||||
14
db/seed.go
14
db/seed.go
@@ -58,12 +58,12 @@ func GetSeedData() (items []Item, boxes []Box, boxitems []BoxItem) {
|
|||||||
func CreateTables(client *sql.DB) (int64, error) {
|
func CreateTables(client *sql.DB) (int64, error) {
|
||||||
script, err := os.ReadFile("/home/mikayla/go/go-htmx-tailwind-example/db/seed.sql")
|
script, err := os.ReadFile("/home/mikayla/go/go-htmx-tailwind-example/db/seed.sql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := client.Exec(string(script))
|
result, err := client.Exec(string(script))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.RowsAffected()
|
return result.RowsAffected()
|
||||||
@@ -86,6 +86,11 @@ func SeedDB() (int64, error) {
|
|||||||
for i := range(items) {
|
for i := range(items) {
|
||||||
_, err := PostItem(items[i])
|
_, err := PostItem(items[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// ignore unique constraint violations and continue
|
||||||
|
if err.Error() == "UNIQUE constraint failed: items.Name" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
insertCount++
|
insertCount++
|
||||||
@@ -94,6 +99,11 @@ func SeedDB() (int64, error) {
|
|||||||
for i := range(boxes) {
|
for i := range(boxes) {
|
||||||
_, err := PostBox(boxes[i])
|
_, err := PostBox(boxes[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// ignore unique constraint violations and continue
|
||||||
|
if err.Error() == "UNIQUE constraint failed: boxes.Name" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
insertCount++
|
insertCount++
|
||||||
|
|||||||
157
db/sql.go
157
db/sql.go
@@ -2,13 +2,33 @@ package db
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateClient() (db *sql.DB, err error) {
|
func CreateClient() (db *sql.DB, err error) {
|
||||||
return sql.Open("sqlite3", "./example.db")
|
return sql.Open("sqlite3", "./example.db")
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllItems() (result []Item, err error) {
|
func GetAllItems() (rows *sql.Rows, err error) {
|
||||||
|
db, err := CreateClient()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
rows, err = db.Query("SELECT * FROM items")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// fmt.Println("rows", rows)
|
||||||
|
|
||||||
|
defer rows.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAll(table EntityLabel) (rows *sql.Rows, err error) {
|
||||||
db, err := CreateClient()
|
db, err := CreateClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -16,46 +36,50 @@ func GetAllItems() (result []Item, err error) {
|
|||||||
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
rows, err := db.Query("SELECT * FROM items")
|
rows, err = db.Query("SELECT * FROM ?", table)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for rows.Next() {
|
func GetByID(table EntityLabel, id int) (row *sql.Row, err error) {
|
||||||
item := Item{}
|
db, err := CreateClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
err = rows.Scan(&item.ID, &item.Name, &item.Notes, &item.Description, &item.Stage, &item.Category)
|
defer db.Close()
|
||||||
|
|
||||||
|
row = db.QueryRow("SELECT * FROM ? WHERE id = ?", table, id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Put[T Entity](table EntityLabel, record Entity) (sql.Result, error) {
|
||||||
|
db, err := CreateClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
query := `UPDATE ? SET name = ?, notes = ?, description = ?, stage = ?, category = ? WHERE id = ?`
|
||||||
|
|
||||||
|
result, err := db.Exec(query, table, record.Name, record.Notes, record.Description, record.Stage, record.Category, record.ID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result = append(result, item)
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
func PostItem(record Item) (sql.Result, error) {
|
||||||
}
|
|
||||||
|
|
||||||
func GetItemByID(id int) (item Item, err error) {
|
|
||||||
db, err := CreateClient()
|
db, err := CreateClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Item{}, err
|
return nil, err
|
||||||
}
|
|
||||||
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
row := db.QueryRow("SELECT * FROM items WHERE id = ?", id)
|
|
||||||
err = row.Scan(&item.ID, &item.Name, &item.Notes, &item.Description, &item.Stage, &item.Category)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func PostItem(item Item) (int64, error) {
|
|
||||||
db, err := CreateClient()
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
@@ -63,37 +87,16 @@ func PostItem(item Item) (int64, error) {
|
|||||||
query := `INSERT INTO items (name, notes, description, stage, category)
|
query := `INSERT INTO items (name, notes, description, stage, category)
|
||||||
VALUES (?, ?, ?, ?, ?)`
|
VALUES (?, ?, ?, ?, ?)`
|
||||||
|
|
||||||
result, err := db.Exec(query, item.Name, item.Notes, item.Description, item.Stage, item.Category)
|
result, err := db.Exec(query, record.Name, record.Notes, record.Description, record.Stage, record.Category)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.LastInsertId()
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PostBox(record Box) (sql.Result, error) {
|
||||||
|
|
||||||
func PostBox(box Box) (int64, error) {
|
|
||||||
db, err := CreateClient()
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
query := `INSERT INTO boxes (name, notes, description, stage, category) VALUES (?, ?, ?, ?, ?)`
|
|
||||||
|
|
||||||
result, err := db.Exec(query, box.Name, box.Notes, box.Description, box.Stage, box.Category)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.LastInsertId()
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetAllBoxes() (result []Box, err error) {
|
|
||||||
db, err := CreateClient()
|
db, err := CreateClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -101,34 +104,50 @@ func GetAllBoxes() (result []Box, err error) {
|
|||||||
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
rows, err := db.Query("SELECT * FROM boxes")
|
query := `INSERT INTO boxes (name, notes, description, stage, category)
|
||||||
if err != nil {
|
VALUES (?, ?, ?, ?, ?)`
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer rows.Close()
|
result, err := db.Exec(query, record.Name, record.Notes, record.Description, record.Stage, record.Category)
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
box := Box{}
|
|
||||||
|
|
||||||
err = rows.Scan(&box.ID, &box.Name, &box.Notes, &box.Description, &box.Stage, &box.Category)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result = append(result, box)
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Delete(table EntityLabel, id int) (sql.Result, error) {
|
||||||
|
db, err := CreateClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
query := `DELETE FROM ? WHERE id = ?`
|
||||||
|
|
||||||
|
return db.Exec(query, table, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseItem(item *Item, scan func(dest ...any) error) (err error) {
|
||||||
|
return scan(&item.ID, &item.Name, &item.Notes, &item.Description, &item.Stage, &item.Category)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseBox(box *Box, scan func(dest ...any) error) error {
|
||||||
|
return scan(&box.ID, &box.Name, &box.Notes, &box.Description, &box.Stage, &box.Category)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseEntityFromBytes(b []byte) (entity Entity, err error) {
|
||||||
|
err = json.Unmarshal(b, &entity)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// func PostBoxItem(itemid int, boxid int) (int64, error) {
|
func ParseItemFromBytes(b []byte) (item Item, err error) {
|
||||||
// db, err := CreateClient()
|
err = json.Unmarshal(b, &item)
|
||||||
// if err != nil {
|
return
|
||||||
// return -1, err
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// defer db.Close()
|
func ParseBoxFromBytes(b []byte) (box Box, err error) {
|
||||||
// // query :=
|
err = json.Unmarshal(b, &box)
|
||||||
// }
|
return
|
||||||
|
}
|
||||||
|
|||||||
12
main.go
12
main.go
@@ -34,10 +34,14 @@ func main() {
|
|||||||
|
|
||||||
//exit process immediately upon sigterm
|
//exit process immediately upon sigterm
|
||||||
handleSigTerms()
|
handleSigTerms()
|
||||||
db.SeedDB()
|
i, err := db.SeedDB()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("seeded db with %d records\n", i)
|
||||||
|
|
||||||
//parse templates
|
//parse templates
|
||||||
var err error
|
|
||||||
html, err = web.TemplateParseFSRecursive(templateFS, ".html", true, nil)
|
html, err = web.TemplateParseFSRecursive(templateFS, ".html", true, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -52,7 +56,11 @@ func main() {
|
|||||||
|
|
||||||
router.Handle("/", web.Action(routes.HomePage))
|
router.Handle("/", web.Action(routes.HomePage))
|
||||||
router.Handle("/items", web.Action(routes.Items(html).GetAll))
|
router.Handle("/items", web.Action(routes.Items(html).GetAll))
|
||||||
|
router.Handle("/items/{id}", web.Action(routes.Items(html).GetByID))
|
||||||
router.Handle("/boxes", web.Action(routes.Boxes(html).GetAll))
|
router.Handle("/boxes", web.Action(routes.Boxes(html).GetAll))
|
||||||
|
router.Handle("/unrelated", web.Action(func(r *http.Request) *web.Response {
|
||||||
|
return web.HTML(http.StatusOK, html, "row-edit.html", nil, nil)
|
||||||
|
}))
|
||||||
|
|
||||||
//logging/tracing
|
//logging/tracing
|
||||||
nextRequestID := func() string {
|
nextRequestID := func() string {
|
||||||
|
|||||||
@@ -3,17 +3,10 @@ package routes
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/innocuous-symmetry/moving-mgmt/db"
|
||||||
"github.com/jritsema/gotoolbox/web"
|
"github.com/jritsema/gotoolbox/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Entity int
|
|
||||||
|
|
||||||
const (
|
|
||||||
Item Entity = iota
|
|
||||||
Box
|
|
||||||
BoxItem
|
|
||||||
)
|
|
||||||
|
|
||||||
type RouterActions struct {
|
type RouterActions struct {
|
||||||
GetAll func(r *http.Request) *web.Response
|
GetAll func(r *http.Request) *web.Response
|
||||||
GetByID func(r *http.Request) *web.Response
|
GetByID func(r *http.Request) *web.Response
|
||||||
@@ -23,8 +16,7 @@ type RouterActions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Router struct {
|
type Router struct {
|
||||||
Entity Entity
|
Entity db.EntityLabel
|
||||||
Path string
|
|
||||||
GetAll func(r *http.Request) *web.Response
|
GetAll func(r *http.Request) *web.Response
|
||||||
GetByID func(r *http.Request) *web.Response
|
GetByID func(r *http.Request) *web.Response
|
||||||
Post func(r *http.Request) *web.Response
|
Post func(r *http.Request) *web.Response
|
||||||
@@ -32,10 +24,9 @@ type Router struct {
|
|||||||
Delete func(r *http.Request) *web.Response
|
Delete func(r *http.Request) *web.Response
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRouter(entity Entity, path string, actions RouterActions) *Router {
|
func NewRouter(entity db.EntityLabel, actions RouterActions) *Router {
|
||||||
return &Router{
|
return &Router{
|
||||||
Entity: entity,
|
Entity: entity,
|
||||||
Path: path,
|
|
||||||
GetAll: actions.GetAll,
|
GetAll: actions.GetAll,
|
||||||
GetByID: actions.GetByID,
|
GetByID: actions.GetByID,
|
||||||
Post: actions.Post,
|
Post: actions.Post,
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ func Boxes(_html *template.Template) *Router {
|
|||||||
html = _html
|
html = _html
|
||||||
|
|
||||||
return NewRouter(
|
return NewRouter(
|
||||||
Box,
|
"boxes",
|
||||||
"/boxes",
|
|
||||||
RouterActions{
|
RouterActions{
|
||||||
GetAll: GetAllBoxes,
|
GetAll: GetAllBoxes,
|
||||||
GetByID: nil,
|
GetByID: nil,
|
||||||
@@ -25,11 +24,23 @@ func Boxes(_html *template.Template) *Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetAllBoxes(_ *http.Request) *web.Response {
|
func GetAllBoxes(_ *http.Request) *web.Response {
|
||||||
result, err := db.GetAllBoxes()
|
result, err := db.GetAll("boxes")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return web.Error(http.StatusBadRequest, err, nil)
|
return web.Error(http.StatusBadRequest, err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boxes := []db.Box{}
|
||||||
|
|
||||||
|
for result.Next() {
|
||||||
|
box := db.Box{}
|
||||||
|
err = db.ParseBox(&box, result.Scan)
|
||||||
|
if err != nil {
|
||||||
|
return web.Error(http.StatusInternalServerError, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
boxes = append(boxes, box)
|
||||||
|
}
|
||||||
|
|
||||||
return web.HTML(
|
return web.HTML(
|
||||||
http.StatusOK,
|
http.StatusOK,
|
||||||
html,
|
html,
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package routes
|
package routes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
// "github.com/innocuous-symmetry/moving-mgmt/"
|
// "github.com/innocuous-symmetry/moving-mgmt/"
|
||||||
db "github.com/innocuous-symmetry/moving-mgmt/db"
|
db "github.com/innocuous-symmetry/moving-mgmt/db"
|
||||||
"github.com/jritsema/gotoolbox/web"
|
"github.com/jritsema/gotoolbox/web"
|
||||||
@@ -12,15 +14,32 @@ var html *template.Template
|
|||||||
|
|
||||||
func HomePage(r *http.Request) *web.Response {
|
func HomePage(r *http.Request) *web.Response {
|
||||||
result, err := db.GetAllItems()
|
result, err := db.GetAllItems()
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return web.Error(http.StatusNotFound, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
items := []db.Item{}
|
||||||
|
for result.Next() {
|
||||||
|
item := db.Item{}
|
||||||
|
err = db.ParseItem(&item, result.Scan)
|
||||||
|
|
||||||
|
fmt.Println("name", item.Name)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return web.Error(http.StatusInternalServerError, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
items = append(items, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
return web.HTML(
|
return web.HTML(
|
||||||
http.StatusOK,
|
http.StatusOK,
|
||||||
html,
|
html,
|
||||||
"index.html",
|
"index.html",
|
||||||
result,
|
items,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package routes
|
package routes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
db "github.com/innocuous-symmetry/moving-mgmt/db"
|
db "github.com/innocuous-symmetry/moving-mgmt/db"
|
||||||
|
"github.com/innocuous-symmetry/moving-mgmt/util"
|
||||||
"github.com/jritsema/gotoolbox/web"
|
"github.com/jritsema/gotoolbox/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,11 +15,10 @@ func Items(_html *template.Template) *Router {
|
|||||||
html = _html
|
html = _html
|
||||||
|
|
||||||
return NewRouter(
|
return NewRouter(
|
||||||
Item,
|
"items",
|
||||||
"/items",
|
|
||||||
RouterActions{
|
RouterActions{
|
||||||
GetAll: GetAllItems,
|
GetAll: GetAllItems,
|
||||||
GetByID: nil,
|
GetByID: GetItemByID,
|
||||||
Post: nil,
|
Post: nil,
|
||||||
Put: nil,
|
Put: nil,
|
||||||
Delete: nil,
|
Delete: nil,
|
||||||
@@ -26,11 +27,26 @@ func Items(_html *template.Template) *Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetAllItems(_ *http.Request) *web.Response {
|
func GetAllItems(_ *http.Request) *web.Response {
|
||||||
result, err := db.GetAllItems()
|
result, err := db.GetAll("items")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return web.Error(http.StatusNotFound, err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
items := []db.Item{}
|
||||||
|
|
||||||
|
for result.Next() {
|
||||||
|
item := db.Item{}
|
||||||
|
err = db.ParseItem(&item, result.Scan)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return web.Error(http.StatusInternalServerError, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("items", items)
|
||||||
|
|
||||||
return web.HTML(
|
return web.HTML(
|
||||||
http.StatusOK,
|
http.StatusOK,
|
||||||
html,
|
html,
|
||||||
@@ -41,14 +57,57 @@ func GetAllItems(_ *http.Request) *web.Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetItemByID(r *http.Request) *web.Response {
|
func GetItemByID(r *http.Request) *web.Response {
|
||||||
var id int
|
id, err := util.GetIDFromPath(r)
|
||||||
id, err := strconv.Atoi(r.URL.Query().Get("id"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return web.Error(http.StatusBadRequest, err, nil)
|
return web.Error(http.StatusBadRequest, err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := db.GetItemByID(id)
|
editMode, err := strconv.ParseBool(r.URL.Query().Get("edit"))
|
||||||
|
if err != nil {
|
||||||
|
return web.Error(http.StatusBadRequest, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := db.GetByID("items", id)
|
||||||
|
|
||||||
|
item := db.Item{}
|
||||||
|
err = db.ParseItem(&item, res.Scan)
|
||||||
|
if err != nil {
|
||||||
|
return web.Error(http.StatusInternalServerError, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tmpl string
|
||||||
|
|
||||||
|
if editMode {
|
||||||
|
tmpl = "entity-edit.html"
|
||||||
|
} else {
|
||||||
|
tmpl = "entity-row.html"
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.HTML(
|
||||||
|
http.StatusOK,
|
||||||
|
html,
|
||||||
|
tmpl,
|
||||||
|
item,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutItem(r *http.Request) *web.Response {
|
||||||
|
body := r.Body
|
||||||
|
defer body.Close()
|
||||||
|
|
||||||
|
bodyBytes := make([]byte, r.ContentLength)
|
||||||
|
_, err := body.Read(bodyBytes)
|
||||||
|
if err != nil {
|
||||||
|
return web.Error(http.StatusInternalServerError, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
item, err := db.ParseEntityFromBytes(bodyBytes)
|
||||||
|
if err != nil {
|
||||||
|
return web.Error(http.StatusBadRequest, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := db.Put("items", item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return web.Error(http.StatusInternalServerError, err, nil)
|
return web.Error(http.StatusInternalServerError, err, nil)
|
||||||
}
|
}
|
||||||
@@ -56,7 +115,7 @@ func GetItemByID(r *http.Request) *web.Response {
|
|||||||
return web.HTML(
|
return web.HTML(
|
||||||
http.StatusOK,
|
http.StatusOK,
|
||||||
html,
|
html,
|
||||||
"item-by-id.html",
|
"entity-row.html",
|
||||||
result,
|
result,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,4 +5,14 @@
|
|||||||
<td class="whitespace-nowrap px-6 py-4">{{.Category}}</td>
|
<td class="whitespace-nowrap px-6 py-4">{{.Category}}</td>
|
||||||
<td class="whitespace-nowrap px-6 py-4">{{.Description}}</td>
|
<td class="whitespace-nowrap px-6 py-4">{{.Description}}</td>
|
||||||
<td class="whitespace-nowrap px-6 py-4">{{.Notes}}</td>
|
<td class="whitespace-nowrap px-6 py-4">{{.Notes}}</td>
|
||||||
|
<td class="whitespace-nowrap px-6 py-4">
|
||||||
|
<button
|
||||||
|
hx-get="/items/{{.ID}}"
|
||||||
|
hx-params="edit=true"
|
||||||
|
hx-target="#datarow-{{.ID}}"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
class="inline-flex items-center h-8 px-4 m-2 text-sm text-blue-100 transition-colors duration-150 bg-blue-700 rounded-lg focus:shadow-outline hover:bg-blue-800"
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||||
<script src="https://unpkg.com/htmx.org@1.9.2"></script>
|
<script src="https://unpkg.com/htmx.org@1.9.2"></script>
|
||||||
<link href="/css/output.css" rel="stylesheet" />
|
<link href="/css/output.css" rel="stylesheet" />
|
||||||
<title>Go + HTMX + Tailwind</title>
|
<title>Mikayla's Move Manager</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main>
|
<main>
|
||||||
@@ -34,7 +34,9 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<span class="text-xl">Items</span>
|
<span class="text-xl">Items</span>
|
||||||
|
|
||||||
<div id="home-page-container">
|
<div id="home-page-container">
|
||||||
{{ template "entity-list.html" . }}
|
{{ template "entity-list.html" . }}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||||
data-include-edit="{{.ID}}"
|
data-include-edit="{{.ID}}"
|
||||||
name="company"
|
name="Name"
|
||||||
value="{{.Company}}"
|
value="{{.Name}}"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap px-6 py-4">
|
<td class="whitespace-nowrap px-6 py-4">
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||||
data-include-edit="{{.ID}}"
|
data-include-edit="{{.ID}}"
|
||||||
name="contact"
|
name="stage"
|
||||||
value="{{.Contact}}"
|
value="{{.Stage}}"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap px-6 py-4">
|
<td class="whitespace-nowrap px-6 py-4">
|
||||||
@@ -23,13 +23,31 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||||
data-include-edit="{{.ID}}"
|
data-include-edit="{{.ID}}"
|
||||||
name="country"
|
name="Category"
|
||||||
value="{{.Country}}"
|
value="{{.Category}}"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap px-6 py-4">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||||
|
data-include-edit="{{.ID}}"
|
||||||
|
name="Description"
|
||||||
|
value="{{.Description}}"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap px-6 py-4">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||||
|
data-include-edit="{{.ID}}"
|
||||||
|
name="Notes"
|
||||||
|
value="{{.Notes}}"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap px-1 py-1">
|
<td class="whitespace-nowrap px-1 py-1">
|
||||||
<a
|
<a
|
||||||
hx-put="/company/{{.ID}}"
|
hx-put="/items/{{.ID}}"
|
||||||
hx-target="#datarow-{{.ID}}"
|
hx-target="#datarow-{{.ID}}"
|
||||||
hx-swap="outerHTML"
|
hx-swap="outerHTML"
|
||||||
hx-indicator="#processing"
|
hx-indicator="#processing"
|
||||||
@@ -41,7 +59,8 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap px-1 py-1">
|
<td class="whitespace-nowrap px-1 py-1">
|
||||||
<a
|
<a
|
||||||
hx-get="/company/{{.ID}}"
|
hx-get="/items/{{.ID}}"
|
||||||
|
hx-params="edit=false"
|
||||||
hx-target="#datarow-{{.ID}}"
|
hx-target="#datarow-{{.ID}}"
|
||||||
hx-swap="outerHTML"
|
hx-swap="outerHTML"
|
||||||
hx-indicator="#processing"
|
hx-indicator="#processing"
|
||||||
|
|||||||
15
util/main.go
Normal file
15
util/main.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetIDFromPath(r *http.Request) (id int, err error) {
|
||||||
|
path := r.URL.Path
|
||||||
|
segments := strings.Split(path, "/")
|
||||||
|
last := segments[len(segments)-1]
|
||||||
|
id, err = strconv.Atoi(last)
|
||||||
|
return
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user