Split app into subpages, persist ingame time, and add 14-month dashboard calendar
This commit is contained in:
172
cmd/server/db.go
Normal file
172
cmd/server/db.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func ensureSchema(db *sql.DB) error {
|
||||
stmts := []string{
|
||||
`CREATE TABLE IF NOT EXISTS settings(
|
||||
id TINYINT PRIMARY KEY,
|
||||
days_per_month INT NOT NULL DEFAULT 2,
|
||||
current_month TINYINT NOT NULL DEFAULT 1,
|
||||
current_day TINYINT NOT NULL DEFAULT 1
|
||||
)`,
|
||||
`INSERT INTO settings(id,days_per_month,current_month,current_day) VALUES (1,2,1,1) ON DUPLICATE KEY UPDATE id=id`,
|
||||
`ALTER TABLE settings ADD COLUMN IF NOT EXISTS current_month TINYINT NOT NULL DEFAULT 1`,
|
||||
`ALTER TABLE settings ADD COLUMN IF NOT EXISTS current_day TINYINT NOT NULL DEFAULT 1`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS fields(
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
number INT NOT NULL UNIQUE,
|
||||
name VARCHAR(120) NOT NULL DEFAULT '',
|
||||
owned TINYINT(1) NOT NULL DEFAULT 0,
|
||||
group_key VARCHAR(64) NOT NULL DEFAULT '',
|
||||
group_name VARCHAR(120) NOT NULL DEFAULT '',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)`,
|
||||
`ALTER TABLE fields ADD COLUMN IF NOT EXISTS owned TINYINT(1) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE fields ADD COLUMN IF NOT EXISTS group_key VARCHAR(64) NOT NULL DEFAULT ''`,
|
||||
`ALTER TABLE fields ADD COLUMN IF NOT EXISTS group_name VARCHAR(120) NOT NULL DEFAULT ''`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS crops(
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(80) NOT NULL UNIQUE,
|
||||
sow_start_month TINYINT NOT NULL,
|
||||
sow_end_month TINYINT NOT NULL,
|
||||
grow_months TINYINT NOT NULL
|
||||
)`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS plans(
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
field_id BIGINT NULL,
|
||||
target_ref VARCHAR(80) NOT NULL DEFAULT '',
|
||||
target_name VARCHAR(140) NOT NULL DEFAULT '',
|
||||
crop_id BIGINT NOT NULL,
|
||||
start_month TINYINT NOT NULL,
|
||||
start_day TINYINT NOT NULL,
|
||||
harvest_month TINYINT NOT NULL,
|
||||
harvest_day TINYINT NOT NULL,
|
||||
notes VARCHAR(255) NOT NULL DEFAULT '',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_plans_fields FOREIGN KEY(field_id) REFERENCES fields(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_plans_crops FOREIGN KEY(crop_id) REFERENCES crops(id) ON DELETE RESTRICT
|
||||
)`,
|
||||
`ALTER TABLE plans MODIFY COLUMN field_id BIGINT NULL`,
|
||||
`ALTER TABLE plans ADD COLUMN IF NOT EXISTS target_ref VARCHAR(80) NOT NULL DEFAULT '' AFTER field_id`,
|
||||
`ALTER TABLE plans ADD COLUMN IF NOT EXISTS target_name VARCHAR(140) NOT NULL DEFAULT '' AFTER target_ref`,
|
||||
}
|
||||
for _, stmt := range stmts {
|
||||
if _, err := db.Exec(stmt); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return seedCrops(db)
|
||||
}
|
||||
|
||||
func (a *App) getSettings() (Settings, error) {
|
||||
var s Settings
|
||||
err := a.db.QueryRow(`SELECT days_per_month,current_month,current_day FROM settings WHERE id=1`).
|
||||
Scan(&s.DaysPerMonth, &s.CurrentMonth, &s.CurrentDay)
|
||||
return s, err
|
||||
}
|
||||
|
||||
func (a *App) listFields() ([]Field, error) {
|
||||
rows, err := a.db.Query(`SELECT id,number,name,owned,COALESCE(group_key,''),COALESCE(group_name,'') FROM fields ORDER BY number`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []Field
|
||||
for rows.Next() {
|
||||
var f Field
|
||||
if err := rows.Scan(&f.ID, &f.Number, &f.Name, &f.Owned, &f.GroupKey, &f.GroupName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, f)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func (a *App) getFieldsByIDs(ids []int64) ([]Field, error) {
|
||||
args := make([]any, 0, len(ids))
|
||||
for _, id := range ids {
|
||||
args = append(args, id)
|
||||
}
|
||||
q := fmt.Sprintf(`SELECT id,number,name,owned,COALESCE(group_key,''),COALESCE(group_name,'') FROM fields WHERE id IN (%s)`, placeholders(len(ids)))
|
||||
rows, err := a.db.Query(q, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []Field
|
||||
for rows.Next() {
|
||||
var f Field
|
||||
if err := rows.Scan(&f.ID, &f.Number, &f.Name, &f.Owned, &f.GroupKey, &f.GroupName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, f)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func (a *App) listCrops() ([]Crop, error) {
|
||||
rows, err := a.db.Query(`SELECT id,name,sow_start_month,sow_end_month,grow_months FROM crops ORDER BY name`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []Crop
|
||||
for rows.Next() {
|
||||
var c Crop
|
||||
if err := rows.Scan(&c.ID, &c.Name, &c.SowStartMonth, &c.SowEndMonth, &c.GrowMonths); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, c)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func (a *App) listPlans() ([]Plan, error) {
|
||||
rows, err := a.db.Query(`
|
||||
SELECT p.id,p.field_id,COALESCE(p.target_ref,''),COALESCE(p.target_name,''),p.crop_id,COALESCE(c.name,''),p.start_month,p.start_day,p.harvest_month,p.harvest_day,COALESCE(p.notes,'')
|
||||
FROM plans p
|
||||
JOIN crops c ON c.id=p.crop_id
|
||||
ORDER BY p.start_month,p.start_day,p.id DESC`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []Plan
|
||||
for rows.Next() {
|
||||
var p Plan
|
||||
if err := rows.Scan(&p.ID, &p.FieldID, &p.TargetRef, &p.TargetName, &p.CropID, &p.CropName, &p.StartMonth, &p.StartDay, &p.HarvestMonth, &p.HarvestDay, &p.Notes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, p)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func seedCrops(db *sql.DB) error {
|
||||
items := []Crop{
|
||||
{Name: "Weizen", SowStartMonth: 9, SowEndMonth: 11, GrowMonths: 10},
|
||||
{Name: "Gerste", SowStartMonth: 9, SowEndMonth: 10, GrowMonths: 9},
|
||||
{Name: "Hafer", SowStartMonth: 3, SowEndMonth: 4, GrowMonths: 4},
|
||||
{Name: "Raps", SowStartMonth: 8, SowEndMonth: 9, GrowMonths: 11},
|
||||
{Name: "Mais", SowStartMonth: 4, SowEndMonth: 5, GrowMonths: 6},
|
||||
{Name: "Sorghum", SowStartMonth: 4, SowEndMonth: 5, GrowMonths: 5},
|
||||
{Name: "Sojabohnen", SowStartMonth: 4, SowEndMonth: 5, GrowMonths: 5},
|
||||
{Name: "Sonnenblumen", SowStartMonth: 4, SowEndMonth: 5, GrowMonths: 5},
|
||||
{Name: "Kartoffeln", SowStartMonth: 3, SowEndMonth: 4, GrowMonths: 7},
|
||||
{Name: "Zuckerrueben", SowStartMonth: 3, SowEndMonth: 4, GrowMonths: 8},
|
||||
{Name: "Baumwolle", SowStartMonth: 2, SowEndMonth: 3, GrowMonths: 8},
|
||||
}
|
||||
for _, c := range items {
|
||||
if _, err := db.Exec(`INSERT INTO crops(name,sow_start_month,sow_end_month,grow_months) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE sow_start_month=VALUES(sow_start_month),sow_end_month=VALUES(sow_end_month),grow_months=VALUES(grow_months)`, c.Name, c.SowStartMonth, c.SowEndMonth, c.GrowMonths); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user