Compare commits

..

4 Commits

Author SHA1 Message Date
0ca262c2ea use new packages 2024-05-12 15:46:23 -04:00
de0a3b3e85 create config package 2024-05-12 15:46:06 -04:00
9b0597e680 extract types to models package 2024-05-12 15:45:36 -04:00
3ae5ea780e data package handles AppContext and Records 2024-05-12 15:45:19 -04:00
4 changed files with 122 additions and 93 deletions

20
config/config.go Normal file
View File

@ -0,0 +1,20 @@
package config
import (
"os"
"path/filepath"
)
type AppConfig struct {
DataPath string
}
func Load() AppConfig {
// TODO: Handle os.MkdirAll error gracefully
homeDir, _ := os.UserHomeDir()
ketotrackDir := filepath.Join(homeDir, ".ketotrack")
os.MkdirAll(ketotrackDir, 0770) // handle error appropriately
return AppConfig{
DataPath: filepath.Join(ketotrackDir, "records.json"),
}
}

46
data/records.go Normal file
View File

@ -0,0 +1,46 @@
package data
import (
"encoding/json"
"ketotrack/model"
"os"
)
// Record holds a pointer to a Reading or Note.
type Record struct {
Reading *model.Reading `json:"reading,omitempty"`
Note *model.Note `json:"note,omitempty"`
}
// AppContext is the application data store that holds Records
type AppContext struct {
Records []Record
}
// LoadRecords will load records from file
func (ctx *AppContext) LoadRecords(filename string) error {
data, err := os.ReadFile(filename)
if err != nil {
return err
}
return json.Unmarshal(data, &ctx.Records)
}
// SaveRecords will save records to a file
func (ctx *AppContext) SaveRecords(filename string) error {
jsonData, err := json.Marshal(ctx.Records)
if err != nil {
return err
}
return os.WriteFile(filename, jsonData, 0660)
}
// AddReading will add a Reading to the AppContext
func (ctx *AppContext) AddReading(reading model.Reading) {
ctx.Records = append(ctx.Records, Record{Reading: &reading})
}
// AddNote will a add a Note to the AppContext
func (ctx *AppContext) AddNote(note model.Note) {
ctx.Records = append(ctx.Records, Record{Note: &note})
}

106
main.go
View File

@ -2,14 +2,15 @@ package main
import ( import (
"bufio" "bufio"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"time"
"ketotrack/data"
"ketotrack/model"
) )
var recordsFilename string var recordsFilename string
@ -36,89 +37,8 @@ func init() {
recordsFilename = filepath.Join(ketotrackDir, "records.json") recordsFilename = filepath.Join(ketotrackDir, "records.json")
} }
// Record holds a pointer to a Reading or Note.
type Record struct {
Reading *Reading `json:"reading,omitempty"`
Note *Note `json:"note,omitempty"`
}
// Note holds a text note along with the time the note was taken.
type Note struct {
Time time.Time `json:"time"`
Text string `json:"text"`
}
// NewNote returns a new Note
func NewNote(text string) Note {
return Note{
Time: time.Now(),
Text: text,
}
}
// Reading holds the glucose and ketone level measurements along with the time the measurements were taken.
type Reading struct {
Time time.Time `json:"time"`
Glucose float64 `json:"glucose"`
Ketone float64 `json:"ketone"`
GKI float64 `json:"GKI"`
}
// NewReading creates and returns a new Reading instance with the provided glucose and ketone levels, and records
// the current time. The glucose value should be provided in mg/dL, while the ketone level should be in mmol/L.
func NewReading(glucose, ketone float64) Reading {
var gki float64
if ketone == 0 {
gki = 0
} else {
gki = (glucose / 18) / ketone
}
return Reading{
Time: time.Now(),
Glucose: glucose,
Ketone: ketone,
GKI: gki,
}
}
// AppContext is the application data store that holds Records
type AppContext struct {
Records []Record
}
// LoadRecords will load records from file
func (ctx *AppContext) LoadRecords(filename string) error {
data, err := os.ReadFile(filename)
if err != nil {
return err
}
return json.Unmarshal(data, &ctx.Records)
}
// SaveRecords will save records to a file
func (ctx *AppContext) SaveRecords(filename string) error {
jsonData, err := json.Marshal(ctx.Records)
if err != nil {
return err
}
return os.WriteFile(filename, jsonData, 0660)
}
// AddReading will add a Reading to the AppContext
func (ctx *AppContext) AddReading(reading Reading) {
ctx.Records = append(ctx.Records, Record{Reading: &reading})
}
// AddNote will a add a Note to the AppContext
func (ctx *AppContext) AddNote(note Note) {
ctx.Records = append(ctx.Records, Record{Note: &note})
}
func main() { func main() {
// TODO: Write option handlers (handleNewNote, handleNewReading) var appCtx data.AppContext
var appCtx AppContext
if err := appCtx.LoadRecords(recordsFilename); err != nil { if err := appCtx.LoadRecords(recordsFilename); err != nil {
fmt.Printf("Error loading records from file: %s\n", err) fmt.Printf("Error loading records from file: %s\n", err)
@ -164,39 +84,39 @@ func main() {
} }
} }
func getNote() (Note, error) { func getNote() (model.Note, error) {
text, err := getUserInput("Enter note text") text, err := getUserInput("Enter note text")
if err != nil { if err != nil {
return Note{}, err return model.Note{}, err
} }
return NewNote(text), nil return model.NewNote(text), nil
} }
func getReading() (Reading, error) { func getReading() (model.Reading, error) {
// Get glucose reading // Get glucose reading
glucose, err := getUserFloat("Enter glucose reading (mg/dL)") glucose, err := getUserFloat("Enter glucose reading (mg/dL)")
if err != nil { if err != nil {
return Reading{}, fmt.Errorf("error getting glucose reading: %w", err) return model.Reading{}, fmt.Errorf("error getting glucose reading: %w", err)
} }
// Validate glucose reading // Validate glucose reading
if glucose <= 0 { if glucose <= 0 {
return Reading{}, errors.New("glucose reading cannot be less than or equal to 0") return model.Reading{}, errors.New("glucose reading cannot be less than or equal to 0")
} }
// Get ketone reading // Get ketone reading
ketone, err := getUserFloat("Enter ketone reading (mmol/L)") ketone, err := getUserFloat("Enter ketone reading (mmol/L)")
if err != nil { if err != nil {
return Reading{}, fmt.Errorf("error getting ketone reading: %w", err) return model.Reading{}, fmt.Errorf("error getting ketone reading: %w", err)
} }
// Validate ketone reading // Validate ketone reading
if ketone < 0 { if ketone < 0 {
fmt.Println("") fmt.Println("")
return Reading{}, errors.New("ketone reading cannot be less than 0") return model.Reading{}, errors.New("ketone reading cannot be less than 0")
} }
reading := NewReading(glucose, ketone) reading := model.NewReading(glucose, ketone)
// Display GKI and level of ketosis // Display GKI and level of ketosis
fmt.Printf("\nYour GKI is: %0.2f\n", reading.GKI) fmt.Printf("\nYour GKI is: %0.2f\n", reading.GKI)

43
model/types.go Normal file
View File

@ -0,0 +1,43 @@
package model
import "time"
// Note holds a text note along with the time the note was taken.
type Note struct {
Time time.Time `json:"time"`
Text string `json:"text"`
}
// NewNote returns a new Note
func NewNote(text string) Note {
return Note{
Time: time.Now(),
Text: text,
}
}
// Reading holds the glucose and ketone level measurements along with the time the measurements were taken.
type Reading struct {
Time time.Time `json:"time"`
Glucose float64 `json:"glucose"`
Ketone float64 `json:"ketone"`
GKI float64 `json:"GKI"`
}
// NewReading creates and returns a new Reading instance with the provided glucose and ketone levels, and records
// the current time. The glucose value should be provided in mg/dL, while the ketone level should be in mmol/L.
func NewReading(glucose, ketone float64) Reading {
var gki float64
if ketone == 0 {
gki = 0
} else {
gki = (glucose / 18) / ketone
}
return Reading{
Time: time.Now(),
Glucose: glucose,
Ketone: ketone,
GKI: gki,
}
}