Add the whole api stack for weight
This commit is contained in:
44
app.go
44
app.go
@@ -80,6 +80,50 @@ func (a *App) GetYearlyFood() WailsAggregateFood {
|
|||||||
return WailsAggregateFood{Data: data, Success: true}
|
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
|
// region settings
|
||||||
func (a *App) GetSettings() settings {
|
func (a *App) GetSettings() settings {
|
||||||
return Settings
|
return Settings
|
||||||
|
@@ -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))
|
row, err := s.db.readConn.Query(fmt.Sprintf("SELECT %s from foodYearly LIMIT %d", foodAggregatedColumns, Settings.FoodYearlyLookback))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error getting daily yearly: %v", err)
|
log.Printf("error getting yearly food: %v", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
47
frontend/src/lib/components/Weight/EmptyWeightComp.svelte
Normal file
47
frontend/src/lib/components/Weight/EmptyWeightComp.svelte
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { toast } from 'svelte-sonner'
|
||||||
|
import type { Err } from '$lib/types'
|
||||||
|
import { type Weight, WeightService } from '$lib/database/weight'
|
||||||
|
import { weightStore } from '$lib/store/weight/weightStore'
|
||||||
|
import { RefreshStores } from '$lib/utils'
|
||||||
|
|
||||||
|
let item: Weight = {
|
||||||
|
weight: 0
|
||||||
|
}
|
||||||
|
let weight: string | null = null
|
||||||
|
|
||||||
|
async function update(event: KeyboardEvent & { currentTarget: (EventTarget & HTMLTableCellElement) }) {
|
||||||
|
if (!weight) return
|
||||||
|
weight = weight.trim()
|
||||||
|
|
||||||
|
if (event.key == 'Enter') {
|
||||||
|
event.preventDefault()
|
||||||
|
item.weight = parseFloat(weight)
|
||||||
|
|
||||||
|
const [dbRow, err]: [Weight, Err] = await WeightService.Create(item)
|
||||||
|
weight = ''
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
toast.error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
RefreshStores()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<tr class="border-b border-gray-200 dark:border-gray-700 text-lg font-bold">
|
||||||
|
<th class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap bg-gray-50 dark:text-white dark:bg-gray-800"
|
||||||
|
scope="row">
|
||||||
|
</th>
|
||||||
|
<td bind:innerText={weight}
|
||||||
|
class:border-[3px]={!weight}
|
||||||
|
class:border-red-600={!weight}
|
||||||
|
class="px-6 py-4 overflow-hidden"
|
||||||
|
contenteditable="true"
|
||||||
|
autofocus
|
||||||
|
on:keydown={update}>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
45
frontend/src/lib/components/Weight/WeightComp.svelte
Normal file
45
frontend/src/lib/components/Weight/WeightComp.svelte
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { type Weight, WeightService } from '$lib/database/weight'
|
||||||
|
|
||||||
|
export let item: Weight
|
||||||
|
export let dateColor: string
|
||||||
|
|
||||||
|
let weight: string = item.weight.toString()
|
||||||
|
|
||||||
|
async function update(event: KeyboardEvent & { currentTarget: (EventTarget & HTMLTableCellElement) }) {
|
||||||
|
if (event.key == 'Enter') {
|
||||||
|
event.preventDefault()
|
||||||
|
await updateItem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function focusOutUpdate() {
|
||||||
|
await updateItem()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateItem() {
|
||||||
|
weight = weight.trim()
|
||||||
|
|
||||||
|
item.weight = weight
|
||||||
|
|
||||||
|
const [newItem, err] = await WeightService.Update(item)
|
||||||
|
|
||||||
|
if (newItem && !err) {
|
||||||
|
item = newItem
|
||||||
|
}
|
||||||
|
weight = item.weight
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<tr class="border-b border-gray-200 dark:border-gray-700 font-bold text-lg">
|
||||||
|
<th class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap bg-gray-50 dark:text-white dark:bg-gray-800"
|
||||||
|
style="color: {dateColor}"
|
||||||
|
scope="row">
|
||||||
|
{item.date}
|
||||||
|
</th>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
{item.weight}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
50
frontend/src/lib/components/Weight/WeightTable.svelte
Normal file
50
frontend/src/lib/components/Weight/WeightTable.svelte
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { GenerateColor } from '$lib/utils'
|
||||||
|
import EmptyWeightComp from '$components/Weight/EmptyWeightComp.svelte'
|
||||||
|
import WeightComp from '$components/Weight/WeightComp.svelte'
|
||||||
|
import type { Weight } from '$lib/database/weight'
|
||||||
|
|
||||||
|
export let items: Weight[] = []
|
||||||
|
|
||||||
|
const dateColors: Map<string, string> = new Map<string, string>()
|
||||||
|
|
||||||
|
function getDateColor(item: Weight): string {
|
||||||
|
if (!item) return GenerateColor()
|
||||||
|
if (!item.date) return GenerateColor()
|
||||||
|
const date = item.date.toString().split(' ')[0]
|
||||||
|
if (!date) return GenerateColor()
|
||||||
|
if (!dateColors.has(date)) dateColors.set(date, GenerateColor())
|
||||||
|
// THERE'S NOTHING UNDEFINED HERE
|
||||||
|
// WE GOT RID OF UNDEFINED ON LINE 33
|
||||||
|
// ASSHOLE
|
||||||
|
// @ts-ignore
|
||||||
|
return dateColors.get(date)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="relative flex flex-col flex-grow h-[95vh]" data-vaul-drawer-wrapper id="page">
|
||||||
|
<div class="relative overflow-auto h-full shadow-md sm:rounded-lg">
|
||||||
|
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
|
||||||
|
<thead class="text-xs text-gray-700 uppercase dark:text-gray-400">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 bg-gray-50 dark:bg-gray-800 w-2/12" scope="col">
|
||||||
|
Date
|
||||||
|
</th>
|
||||||
|
<th class="px-6 py-3 w-10/12" scope="col">
|
||||||
|
Weight
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<EmptyWeightComp />
|
||||||
|
{#each items as f}
|
||||||
|
<WeightComp item="{f}" dateColor="{getDateColor(f)}" />
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
8
frontend/src/lib/router/routes/Weight/Weight.svelte
Normal file
8
frontend/src/lib/router/routes/Weight/Weight.svelte
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import WeightTable from '$components/Weight/WeightTable.svelte'
|
||||||
|
import { weightStore } from '$lib/store/weight/weightStore'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<WeightTable items="{$weightStore}" />
|
||||||
|
</template>
|
12
frontend/wailsjs/go/main/App.d.ts
vendored
12
frontend/wailsjs/go/main/App.d.ts
vendored
@@ -4,20 +4,32 @@ import {main} from '../models';
|
|||||||
|
|
||||||
export function CreateFood(arg1:main.Food):Promise<main.WailsFood1>;
|
export function CreateFood(arg1:main.Food):Promise<main.WailsFood1>;
|
||||||
|
|
||||||
|
export function CreateWeight(arg1:main.Weight):Promise<main.WailsWeight1>;
|
||||||
|
|
||||||
export function GetDailyFood():Promise<main.WailsAggregateFood>;
|
export function GetDailyFood():Promise<main.WailsAggregateFood>;
|
||||||
|
|
||||||
|
export function GetDailyWeight():Promise<main.WailsAggregateWeight>;
|
||||||
|
|
||||||
export function GetFood():Promise<main.WailsFood>;
|
export function GetFood():Promise<main.WailsFood>;
|
||||||
|
|
||||||
export function GetLastPer100(arg1:string):Promise<main.WailsPer100>;
|
export function GetLastPer100(arg1:string):Promise<main.WailsPer100>;
|
||||||
|
|
||||||
export function GetMonthlyFood():Promise<main.WailsAggregateFood>;
|
export function GetMonthlyFood():Promise<main.WailsAggregateFood>;
|
||||||
|
|
||||||
|
export function GetMonthlyWeight():Promise<main.WailsAggregateWeight>;
|
||||||
|
|
||||||
export function GetSettings():Promise<main.settings>;
|
export function GetSettings():Promise<main.settings>;
|
||||||
|
|
||||||
export function GetWeeklyFood():Promise<main.WailsAggregateFood>;
|
export function GetWeeklyFood():Promise<main.WailsAggregateFood>;
|
||||||
|
|
||||||
|
export function GetWeeklyWeight():Promise<main.WailsAggregateWeight>;
|
||||||
|
|
||||||
|
export function GetWeight():Promise<main.WailsWeight>;
|
||||||
|
|
||||||
export function GetYearlyFood():Promise<main.WailsAggregateFood>;
|
export function GetYearlyFood():Promise<main.WailsAggregateFood>;
|
||||||
|
|
||||||
|
export function GetYearlyWeight():Promise<main.WailsAggregateWeight>;
|
||||||
|
|
||||||
export function SetSetting(arg1:string,arg2:number):Promise<main.WailsGenericAck>;
|
export function SetSetting(arg1:string,arg2:number):Promise<main.WailsGenericAck>;
|
||||||
|
|
||||||
export function UpdateFood(arg1:main.Food):Promise<main.WailsFood1>;
|
export function UpdateFood(arg1:main.Food):Promise<main.WailsFood1>;
|
||||||
|
@@ -6,10 +6,18 @@ export function CreateFood(arg1) {
|
|||||||
return window['go']['main']['App']['CreateFood'](arg1);
|
return window['go']['main']['App']['CreateFood'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function CreateWeight(arg1) {
|
||||||
|
return window['go']['main']['App']['CreateWeight'](arg1);
|
||||||
|
}
|
||||||
|
|
||||||
export function GetDailyFood() {
|
export function GetDailyFood() {
|
||||||
return window['go']['main']['App']['GetDailyFood']();
|
return window['go']['main']['App']['GetDailyFood']();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function GetDailyWeight() {
|
||||||
|
return window['go']['main']['App']['GetDailyWeight']();
|
||||||
|
}
|
||||||
|
|
||||||
export function GetFood() {
|
export function GetFood() {
|
||||||
return window['go']['main']['App']['GetFood']();
|
return window['go']['main']['App']['GetFood']();
|
||||||
}
|
}
|
||||||
@@ -22,6 +30,10 @@ export function GetMonthlyFood() {
|
|||||||
return window['go']['main']['App']['GetMonthlyFood']();
|
return window['go']['main']['App']['GetMonthlyFood']();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function GetMonthlyWeight() {
|
||||||
|
return window['go']['main']['App']['GetMonthlyWeight']();
|
||||||
|
}
|
||||||
|
|
||||||
export function GetSettings() {
|
export function GetSettings() {
|
||||||
return window['go']['main']['App']['GetSettings']();
|
return window['go']['main']['App']['GetSettings']();
|
||||||
}
|
}
|
||||||
@@ -30,10 +42,22 @@ export function GetWeeklyFood() {
|
|||||||
return window['go']['main']['App']['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() {
|
export function GetYearlyFood() {
|
||||||
return window['go']['main']['App']['GetYearlyFood']();
|
return window['go']['main']['App']['GetYearlyFood']();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function GetYearlyWeight() {
|
||||||
|
return window['go']['main']['App']['GetYearlyWeight']();
|
||||||
|
}
|
||||||
|
|
||||||
export function SetSetting(arg1, arg2) {
|
export function SetSetting(arg1, arg2) {
|
||||||
return window['go']['main']['App']['SetSetting'](arg1, arg2);
|
return window['go']['main']['App']['SetSetting'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,20 @@ export namespace main {
|
|||||||
this.energy = source["energy"];
|
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 {
|
export class Food {
|
||||||
rowid: number;
|
rowid: number;
|
||||||
date: string;
|
date: string;
|
||||||
@@ -76,6 +90,40 @@ export namespace main {
|
|||||||
return a;
|
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 {
|
export class WailsFood {
|
||||||
data: Food[];
|
data: Food[];
|
||||||
success: boolean;
|
success: boolean;
|
||||||
@@ -174,6 +222,91 @@ export namespace main {
|
|||||||
this.error = source["error"];
|
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 {
|
export class settings {
|
||||||
foodDaysLookback: number;
|
foodDaysLookback: number;
|
||||||
foodAggregatedDaysLookback: number;
|
foodAggregatedDaysLookback: number;
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// Wails doesn't rlike generics... Fuck...
|
// Wails doesn't rlike generics... Fuck...
|
||||||
// WailsReturn[T interface{}] struct {
|
// WailsReturn[T interface{}] struct {
|
||||||
@@ -31,18 +29,24 @@ type (
|
|||||||
Error string `json:"error,omitempty"`
|
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 {
|
WailsGenericAck struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
Weight struct {
|
|
||||||
rowid int
|
|
||||||
date time.Time
|
|
||||||
weight float32
|
|
||||||
}
|
|
||||||
AggregatedWeight struct {
|
|
||||||
period string
|
|
||||||
amount float32
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
193
weightservice.go
193
weightservice.go
@@ -1,5 +1,192 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
type WeightService struct {
|
import (
|
||||||
db *DB
|
"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
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user