Implement basic food service
This commit is contained in:
187
food.ddl
Normal file
187
food.ddl
Normal 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;
|
103
foodservice.go
103
foodservice.go
@@ -1,5 +1,104 @@
|
||||
package main
|
||||
|
||||
type FoodService struct {
|
||||
db *DB
|
||||
import (
|
||||
"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
17
main.go
@@ -53,7 +53,22 @@ func main() {
|
||||
Error.Printf("%++v", err)
|
||||
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")
|
||||
wg.Wait()
|
||||
|
16
types.go
16
types.go
@@ -3,21 +3,7 @@ package main
|
||||
import "time"
|
||||
|
||||
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 {
|
||||
rowid int
|
||||
date time.Time
|
||||
|
Reference in New Issue
Block a user