Implement basic food service

This commit is contained in:
2024-08-09 16:21:11 +02:00
parent b265a06ce7
commit a23ada9bb0
4 changed files with 305 additions and 18 deletions

187
food.ddl Normal file
View File

@@ -0,0 +1,187 @@
begin transaction;
create table weight (
date datetime default (datetime('now', '+2 hours')),
weight real not null
);
-- begin TRANSACTION;
-- drop table if exists weight2;
-- create table weight2 (
-- date datetime default (datetime('now', '+2 hours')),
-- weight real not null
-- );
-- insert into weight2(date, weight)
-- select date, weight from weight;
-- drop table weight;
-- alter table weight2 rename to weight;
-- commit;
create index weightDateIdx on weight(date);
create index weightDailyIdx on weight(strftime('%Y-%m-%d', date));
create index weightWeeklyIdx on weight(strftime('%Y-%W', date));
create index weightMonthlyIdx on weight(strftime('%Y-%m', date));
create index weightYearlyIdx on weight(strftime('%Y', date));
drop view if exists weightView;
drop view if exists weightDaily;
drop view if exists weightWeekly;
drop view if exists weightMonthly;
drop view if exists weightYearly;
create view weightView as
select rowid,
date,
round(weight, 2) as weight
from weight
order by date desc;
-- Daily Summary View
create view weightDaily as
select strftime('%Y-%m-%d', date) as period,
round(avg(weight), 2) as amount
from weight
group by strftime('%Y-%m-%d', date)
order by date desc;
-- Weekly Summary View
create view weightWeekly as
select strftime('%Y-%W', date) as period,
round(avg(weight), 2) as amount
from weight
group by strftime('%Y-%W', date)
order by date desc;
-- Monthly Summary View
create view weightMonthly as
select strftime('%Y-%m', date) as period,
round(avg(weight), 2) as amount
from weight
group by strftime('%Y-%m', date)
order by date desc;
-- Yearly Summary View
create view weightYearly as
select strftime('%Y', date) as period,
round(avg(weight), 2) as amount
from weight
group by strftime('%Y', date)
order by date desc;
create table food(
date datetime default (datetime('now', '+2 hours')),
food varchar not null,
description varchar,
amount real not null,
per100 real default 0,
energy generated always as (coalesce(amount, 0) * coalesce(per100, 0) / 100) stored
);
-- begin transaction;
-- drop table if exists food2;
-- create table food2(
-- date datetime default (datetime('now', '+2 hours')),
-- food varchar not null,
-- description varchar,
-- amount real not null,
-- per100 real default 0,
-- energy generated always as (coalesce(amount, 0) * coalesce(per100, 0) / 100) stored
-- );
-- insert into food2(date, food, description, amount, per100)
-- select date, food, description, amount, per100 from food;
-- drop table food;
-- alter table food2 rename to food;
-- commit;
create index dailyIdx on food(strftime('%Y-%m-%d', date));
create index weeklyIdx on food(strftime('%Y-%W', date));
create index monthlyIdx on food(strftime('%Y-%m', date));
create index yearlyIdx on food(strftime('%Y', date));
create index dateIdx on food(date);
create index foodIdx on food(food);
drop view if exists foodView;
drop view if exists daily;
drop view if exists weekly;
drop view if exists monthly;
drop view if exists yearly;
drop view if exists recent;
create view foodView as
select rowid,
date,
food,
description,
round(amount, 2) as amount,
round(per100, 2) as per100,
round(energy, 2) as energy
from food;
-- Daily Summary View
create view daily as
select strftime('%Y-%m-%d', date) as period,
round(sum(amount), 2) as amount,
round(avg(per100), 2) as avgPer100,
round(sum(energy), 2) as energy
from food
group by strftime('%Y-%m-%d', date)
order by date desc;
-- Weekly Summary View
create view weekly as
select strftime('%Y-%W', date) as period,
round(sum(amount), 2) as amount,
round(avg(per100), 2) as avgPer100,
round(sum(energy), 2) as energy
from food
group by strftime('%Y-%W', date)
order by date desc;
-- Monthly Summary View
create view monthly as
select strftime('%Y-%m', date) as period,
round(sum(amount), 2) as amount,
round(avg(per100), 2) as avgPer100,
round(sum(energy), 2) as energy
from food
group by strftime('%Y-%m', date)
order by date desc;
-- Yearly Summary View
create view yearly as
select strftime('%Y', date) as period,
round(sum(amount), 2) as amount,
round(avg(per100), 2) as avgPer100,
round(sum(energy), 2) as energy
from food
group by strftime('%Y', date)
order by date desc;
-- Recent
create view recent as
select rowid,
*
from food
order by date desc
limit 10;
drop trigger if exists getper100;
create trigger getper100 after
insert on food
begin
update food
set per100 = coalesce(
new .per100,
(
select per100
from food
where food = new .food
and per100 is not null
order by date desc
limit 1
)
)
where rowid = new .rowid;
end;
create table settings (key text, value text) --rollback;
commit;

View File

@@ -1,5 +1,104 @@
package main package main
type FoodService struct { import (
db *DB "database/sql"
"fmt"
"log"
)
type (
FoodService struct {
db *DB
}
Food struct {
rowid int
date string
food string
descripton string
amount float32
per100 float32
energy float32
}
AggregatedFood struct {
period string
amount float32
avgPer100 float32
energy float32
}
)
const foodColumns = "rowid, date, food, description, amount, per100, energy"
const foodAggregatedColumns = "period, amount, avgPer100, energy"
func (s *FoodService) GetRecent() ([]Food, error) {
var res []Food
if s.db == nil || !s.db.Ready {
return res, fmt.Errorf("cannot get recent food, db is nil or is not ready")
}
row, _ := s.db.readConn.Query(fmt.Sprintf("SELECT %s from foodView WHERE date > datetime('now', '-%s days')", foodColumns, Settings.FoodDaysLookback))
var rows []Food
for row.Next() {
var food Food
err := row.Scan(&food.rowid, &food.date, &food.food, &food.descripton, &food.amount, &food.per100, &food.energy)
if err != nil {
log.Printf("error scanning row: %v", err)
continue
}
rows = append(rows, food)
}
log.Printf("%++v", rows)
return res, nil
}
func (s *FoodService) Create(food Food) (Food, error) {
if s.db == nil || !s.db.Ready {
return food, fmt.Errorf("cannot create food, db is nil or is not ready")
}
if food.food == "" {
return food, fmt.Errorf("cannot create food, food is empty")
}
if food.amount <= 0 {
return food, fmt.Errorf("cannot create food, amount is less than or equal to 0")
}
var res sql.Result
var err error
if food.per100 > 0 {
res, err = s.db.writeConn.Exec("INSERT INTO food (food, description, amount, per100) VALUES (?, ?, ?, ?)", food.food, food.descripton, food.amount, food.per100)
if err != nil {
return food, fmt.Errorf("error inserting food: %v", err)
}
} else {
res, err = s.db.writeConn.Exec("INSERT INTO food (food, description, amount) VALUES (?, ?, ?)", food.food, food.descripton, food.amount)
if err != nil {
return food, fmt.Errorf("error inserting food: %v", err)
}
}
rowid, err := res.LastInsertId()
if err != nil {
return food, fmt.Errorf("error getting last insert id: %v", err)
}
return s.GetByRowid(rowid)
}
func (s *FoodService) GetByRowid(rowid int64) (Food, error) {
var res Food
if s.db == nil || !s.db.Ready {
return res, fmt.Errorf("cannot get food by rowid, db is nil or is not ready")
}
row := s.db.readConn.QueryRow(fmt.Sprintf("SELECT %s from foodView WHERE rowid = ?", foodColumns), rowid)
err := row.Scan(&res.rowid, &res.date, &res.food, &res.descripton, &res.amount, &res.per100, &res.energy)
if err != nil {
return res, fmt.Errorf("error scanning row: %v", err)
}
return res, nil
} }

17
main.go
View File

@@ -53,7 +53,22 @@ func main() {
Error.Printf("%++v", err) Error.Printf("%++v", err)
os.Exit(1) os.Exit(1)
} }
log.Println(Settings) log.Printf("Loaded settings as: %++v", Settings)
foodService := FoodService{db: &db}
// _, err = foodService.GetRecent()
// if err != nil {
// Error.Printf("%++v", err)
// os.Exit(1)
// }
food, err := foodService.Create(Food{food: "test", amount: 1})
if err != nil {
Error.Printf("%++v", err)
os.Exit(1)
}
log.Println(food)
log.Println("done") log.Println("done")
wg.Wait() wg.Wait()

View File

@@ -3,21 +3,7 @@ package main
import "time" import "time"
type ( type (
Food struct {
rowid int
date time.Time
food string
descripton string
amount float32
per100 float32
energy float32
}
AggregatedFood struct {
period string
amount float32
avgPer100 float32
energy float32
}
Weight struct { Weight struct {
rowid int rowid int
date time.Time date time.Time