diff --git a/app.go b/app.go index 4984f50..aa26e97 100644 --- a/app.go +++ b/app.go @@ -80,6 +80,50 @@ func (a *App) GetYearlyFood() WailsAggregateFood { return WailsAggregateFood{Data: data, Success: true} } +// region weight +func (a *App) GetWeight() WailsWeight { + data, err := weightService.GetRecent() + if err != nil { + return WailsWeight{Success: false, Error: err.Error()} + } + return WailsWeight{Data: data, Success: true} +} +func (a *App) CreateWeight(weight Weight) WailsWeight1 { + data, err := weightService.Create(weight) + if err != nil { + return WailsWeight1{Success: false, Error: err.Error()} + } + return WailsWeight1{Data: data, Success: true} +} +func (a *App) GetDailyWeight() WailsAggregateWeight { + data, err := weightService.GetDaily() + if err != nil { + return WailsAggregateWeight{Success: false, Error: err.Error()} + } + return WailsAggregateWeight{Data: data, Success: true} +} +func (a *App) GetWeeklyWeight() WailsAggregateWeight { + data, err := weightService.GetWeekly() + if err != nil { + return WailsAggregateWeight{Success: false, Error: err.Error()} + } + return WailsAggregateWeight{Data: data, Success: true} +} +func (a *App) GetMonthlyWeight() WailsAggregateWeight { + data, err := weightService.GetMonthly() + if err != nil { + return WailsAggregateWeight{Success: false, Error: err.Error()} + } + return WailsAggregateWeight{Data: data, Success: true} +} +func (a *App) GetYearlyWeight() WailsAggregateWeight { + data, err := weightService.GetYearly() + if err != nil { + return WailsAggregateWeight{Success: false, Error: err.Error()} + } + return WailsAggregateWeight{Data: data, Success: true} +} + // region settings func (a *App) GetSettings() settings { return Settings diff --git a/foodservice.go b/foodservice.go index 447c584..a235556 100644 --- a/foodservice.go +++ b/foodservice.go @@ -236,7 +236,7 @@ func (s *FoodService) GetYearly() ([]AggregatedFood, error) { row, err := s.db.readConn.Query(fmt.Sprintf("SELECT %s from foodYearly LIMIT %d", foodAggregatedColumns, Settings.FoodYearlyLookback)) if err != nil { - log.Printf("error getting daily yearly: %v", err) + log.Printf("error getting yearly food: %v", err) return res, err } diff --git a/frontend/src/lib/components/Weight/EmptyWeightComp.svelte b/frontend/src/lib/components/Weight/EmptyWeightComp.svelte new file mode 100644 index 0000000..065e7a3 --- /dev/null +++ b/frontend/src/lib/components/Weight/EmptyWeightComp.svelte @@ -0,0 +1,47 @@ + + + diff --git a/frontend/src/lib/components/Weight/WeightComp.svelte b/frontend/src/lib/components/Weight/WeightComp.svelte new file mode 100644 index 0000000..007bdc8 --- /dev/null +++ b/frontend/src/lib/components/Weight/WeightComp.svelte @@ -0,0 +1,45 @@ + + + diff --git a/frontend/src/lib/components/Weight/WeightTable.svelte b/frontend/src/lib/components/Weight/WeightTable.svelte new file mode 100644 index 0000000..2a3574f --- /dev/null +++ b/frontend/src/lib/components/Weight/WeightTable.svelte @@ -0,0 +1,50 @@ + + + diff --git a/frontend/src/lib/router/routes/Weight/Weight.svelte b/frontend/src/lib/router/routes/Weight/Weight.svelte new file mode 100644 index 0000000..866938e --- /dev/null +++ b/frontend/src/lib/router/routes/Weight/Weight.svelte @@ -0,0 +1,8 @@ + + + diff --git a/frontend/wailsjs/go/main/App.d.ts b/frontend/wailsjs/go/main/App.d.ts index ed272ca..d1f690f 100644 --- a/frontend/wailsjs/go/main/App.d.ts +++ b/frontend/wailsjs/go/main/App.d.ts @@ -4,20 +4,32 @@ import {main} from '../models'; export function CreateFood(arg1:main.Food):Promise; +export function CreateWeight(arg1:main.Weight):Promise; + export function GetDailyFood():Promise; +export function GetDailyWeight():Promise; + export function GetFood():Promise; export function GetLastPer100(arg1:string):Promise; export function GetMonthlyFood():Promise; +export function GetMonthlyWeight():Promise; + export function GetSettings():Promise; export function GetWeeklyFood():Promise; +export function GetWeeklyWeight():Promise; + +export function GetWeight():Promise; + export function GetYearlyFood():Promise; +export function GetYearlyWeight():Promise; + export function SetSetting(arg1:string,arg2:number):Promise; export function UpdateFood(arg1:main.Food):Promise; diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js index 2b7b70d..777c883 100644 --- a/frontend/wailsjs/go/main/App.js +++ b/frontend/wailsjs/go/main/App.js @@ -6,10 +6,18 @@ export function CreateFood(arg1) { return window['go']['main']['App']['CreateFood'](arg1); } +export function CreateWeight(arg1) { + return window['go']['main']['App']['CreateWeight'](arg1); +} + export function GetDailyFood() { return window['go']['main']['App']['GetDailyFood'](); } +export function GetDailyWeight() { + return window['go']['main']['App']['GetDailyWeight'](); +} + export function GetFood() { return window['go']['main']['App']['GetFood'](); } @@ -22,6 +30,10 @@ export function GetMonthlyFood() { return window['go']['main']['App']['GetMonthlyFood'](); } +export function GetMonthlyWeight() { + return window['go']['main']['App']['GetMonthlyWeight'](); +} + export function GetSettings() { return window['go']['main']['App']['GetSettings'](); } @@ -30,10 +42,22 @@ export function GetWeeklyFood() { return window['go']['main']['App']['GetWeeklyFood'](); } +export function GetWeeklyWeight() { + return window['go']['main']['App']['GetWeeklyWeight'](); +} + +export function GetWeight() { + return window['go']['main']['App']['GetWeight'](); +} + export function GetYearlyFood() { return window['go']['main']['App']['GetYearlyFood'](); } +export function GetYearlyWeight() { + return window['go']['main']['App']['GetYearlyWeight'](); +} + export function SetSetting(arg1, arg2) { return window['go']['main']['App']['SetSetting'](arg1, arg2); } diff --git a/frontend/wailsjs/go/models.ts b/frontend/wailsjs/go/models.ts index dbacb5a..95ac7ff 100644 --- a/frontend/wailsjs/go/models.ts +++ b/frontend/wailsjs/go/models.ts @@ -18,6 +18,20 @@ export namespace main { this.energy = source["energy"]; } } + export class AggregatedWeight { + period: string; + amount: number; + + static createFrom(source: any = {}) { + return new AggregatedWeight(source); + } + + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.period = source["period"]; + this.amount = source["amount"]; + } + } export class Food { rowid: number; date: string; @@ -76,6 +90,40 @@ export namespace main { return a; } } + export class WailsAggregateWeight { + data: AggregatedWeight[]; + success: boolean; + error?: string; + + static createFrom(source: any = {}) { + return new WailsAggregateWeight(source); + } + + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.data = this.convertValues(source["data"], AggregatedWeight); + this.success = source["success"]; + this.error = source["error"]; + } + + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice && a.map) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } export class WailsFood { data: Food[]; success: boolean; @@ -174,6 +222,91 @@ export namespace main { this.error = source["error"]; } } + export class Weight { + rowid: number; + date: string; + food: number; + + static createFrom(source: any = {}) { + return new Weight(source); + } + + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.rowid = source["rowid"]; + this.date = source["date"]; + this.food = source["food"]; + } + } + export class WailsWeight { + data: Weight[]; + success: boolean; + error?: string; + + static createFrom(source: any = {}) { + return new WailsWeight(source); + } + + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.data = this.convertValues(source["data"], Weight); + this.success = source["success"]; + this.error = source["error"]; + } + + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice && a.map) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } + export class WailsWeight1 { + data: Weight; + success: boolean; + error?: string; + + static createFrom(source: any = {}) { + return new WailsWeight1(source); + } + + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.data = this.convertValues(source["data"], Weight); + this.success = source["success"]; + this.error = source["error"]; + } + + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice && a.map) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } + export class settings { foodDaysLookback: number; foodAggregatedDaysLookback: number; diff --git a/wailstypes.go b/wailstypes.go index 5432ec3..b375476 100644 --- a/wailstypes.go +++ b/wailstypes.go @@ -1,7 +1,5 @@ package main -import "time" - type ( // Wails doesn't rlike generics... Fuck... // WailsReturn[T interface{}] struct { @@ -31,18 +29,24 @@ type ( Error string `json:"error,omitempty"` } + WailsWeight struct { + Data []Weight `json:"data"` + Success bool `json:"success"` + Error string `json:"error,omitempty"` + } + WailsWeight1 struct { + Data Weight `json:"data"` + Success bool `json:"success"` + Error string `json:"error,omitempty"` + } + WailsAggregateWeight struct { + Data []AggregatedWeight `json:"data"` + Success bool `json:"success"` + Error string `json:"error,omitempty"` + } + WailsGenericAck struct { Success bool `json:"success"` Error string `json:"error,omitempty"` } - - Weight struct { - rowid int - date time.Time - weight float32 - } - AggregatedWeight struct { - period string - amount float32 - } ) diff --git a/weightservice.go b/weightservice.go index 77dc104..82286ac 100644 --- a/weightservice.go +++ b/weightservice.go @@ -1,5 +1,192 @@ package main -type WeightService struct { - db *DB -} \ No newline at end of file +import ( + "fmt" + "log" +) + +type ( + WeightService struct { + db *DB + } + Weight struct { + Rowid int64 `json:"rowid"` + Date string `json:"date"` + Weight float32 `json:"weight"` + } + AggregatedWeight struct { + Period string `json:"period"` + Amount float32 `json:"amount"` + } +) + +const weightcolumns = "rowid, date, weight" +const weightAggregatedColumns = "period, amount" + +func (w *WeightService) GetRecent() ([]Weight, error) { + var res []Weight + if w.db == nil || !w.db.Ready { + return res, fmt.Errorf("cannot get recent weight, db is nil or is not ready") + } + + row, err := w.db.readConn.Query(fmt.Sprintf("SELECT %s from weightView WHERE date > datetime('now', '-%d days') order by date desc;", weightcolumns, Settings.WeightDaysLookback)) + if err != nil { + log.Printf("error getting daily weight: %v", err) + return res, err + } + + for row.Next() { + var weight Weight + err := row.Scan(&weight.Rowid, &weight.Date, &weight.Weight) + if err != nil { + log.Printf("error scanning row: %v", err) + continue + } + + res = append(res, weight) + } + + return res, nil +} + +func (w *WeightService) Create(weight Weight) (Weight, error) { + if w.db == nil || !w.db.Ready { + return weight, fmt.Errorf("cannot create weight, db is nil or is not ready") + } + if weight.Weight <= 0 { + return weight, fmt.Errorf("cannot create weight, weight is empty") + } + + res, err := w.db.writeConn.Exec("INSERT INTO weight (weight) VALUES (?)", weight.Weight) + if err != nil { + return weight, fmt.Errorf("error inserting weight: %v", err) + } + + rowid, err := res.LastInsertId() + if err != nil { + return weight, fmt.Errorf("error getting last insert id: %v", err) + } + + return w.GetByRowid(rowid) +} + +func (w *WeightService) GetByRowid(rowid int64) (Weight, error) { + var res Weight + if w.db == nil || !w.db.Ready { + return res, fmt.Errorf("cannot get weight by rowid, db is nil or is not ready") + } + + row := w.db.readConn.QueryRow(fmt.Sprintf("SELECT %s from weightView WHERE rowid = ?", weightcolumns), rowid) + err := row.Scan(&res.Rowid, &res.Date, &res.Weight) + if err != nil { + return res, fmt.Errorf("error scanning row: %v", err) + } + + return res, nil +} + +// I could probably refactor this to be less of a disaster... +// But I think it'll work for now +func (w *WeightService) GetDaily() ([]AggregatedWeight, error) { + var res []AggregatedWeight + if w.db == nil || !w.db.Ready { + return res, fmt.Errorf("cannot get daily weight, db is nil or is not ready") + } + + row, err := w.db.readConn.Query(fmt.Sprintf("SELECT %s from weightDaily LIMIT %d", weightAggregatedColumns, Settings.WeightDailyLookback)) + if err != nil { + log.Printf("error getting daily weight: %v", err) + return res, err + } + + for row.Next() { + var weight AggregatedWeight + err := row.Scan(&weight.Period, &weight.Amount) + if err != nil { + log.Printf("error scanning row: %v", err) + continue + } + + res = append(res, weight) + } + + return res, nil +} + +func (w *WeightService) GetWeekly() ([]AggregatedWeight, error) { + var res []AggregatedWeight + if w.db == nil || !w.db.Ready { + return res, fmt.Errorf("cannot get weekly weight, db is nil or is not ready") + } + + row, err := w.db.readConn.Query(fmt.Sprintf("SELECT %s from weightWeekly LIMIT %d", weightAggregatedColumns, Settings.WeightWeeklyLookback)) + if err != nil { + log.Printf("error getting weekly weight: %v", err) + return res, err + } + + for row.Next() { + var weight AggregatedWeight + err := row.Scan(&weight.Period, &weight.Amount) + if err != nil { + log.Printf("error scanning row: %v", err) + continue + } + + res = append(res, weight) + } + + return res, nil +} + +func (w *WeightService) GetMonthly() ([]AggregatedWeight, error) { + var res []AggregatedWeight + if w.db == nil || !w.db.Ready { + return res, fmt.Errorf("cannot get monthly weight, db is nil or is not ready") + } + + row, err := w.db.readConn.Query(fmt.Sprintf("SELECT %s from weightMonthly LIMIT %d", weightAggregatedColumns, Settings.WeightMonthlyLookback)) + if err != nil { + log.Printf("error getting monthly weight: %v", err) + return res, err + } + + for row.Next() { + var weight AggregatedWeight + err := row.Scan(&weight.Period, &weight.Amount) + if err != nil { + log.Printf("error scanning row: %v", err) + continue + } + + res = append(res, weight) + } + + return res, nil +} + +func (w *WeightService) GetYearly() ([]AggregatedWeight, error) { + var res []AggregatedWeight + if w.db == nil || !w.db.Ready { + return res, fmt.Errorf("cannot get yearly weight, db is nil or is not ready") + } + + row, err := w.db.readConn.Query(fmt.Sprintf("SELECT %s from weightYearly LIMIT %d", weightAggregatedColumns, Settings.WeightYearlyLookback)) + if err != nil { + log.Printf("error getting yearly weight: %v", err) + return res, err + } + + for row.Next() { + var weight AggregatedWeight + err := row.Scan(&weight.Period, &weight.Amount) + if err != nil { + log.Printf("error scanning row: %v", err) + continue + } + + res = append(res, weight) + } + + return res, nil +}