Anki/yamldb.go

139 lines
2.6 KiB
Go

package main
import (
"os"
"time"
"github.com/google/uuid"
"gopkg.in/yaml.v2"
)
type (
yamlDB struct {
addr string
Knowledge knowledge
Users map[IDU]user
}
knowledge struct {
Questions map[IDQ]Question
Answers map[IDA]Answer
}
user struct {
Tags tags
History map[IDQ][]History
}
tags struct {
Assignments []IDT
}
)
func newYamlDB(p string) (yamlDB, error) {
db := yamlDB{
addr: p,
Knowledge: knowledge{
Questions: map[IDQ]Question{},
Answers: map[IDA]Answer{},
},
Users: map[IDU]user{},
}
if b, err := os.ReadFile(p); err != nil {
return yamlDB{}, err
} else if err := yaml.Unmarshal(b, &db); err != nil {
return yamlDB{}, err
}
return db, nil
}
func (db yamlDB) Close() {
if os.Getenv("W") == "" {
return
}
b, err := yaml.Marshal(db)
if err != nil {
panic(err)
}
if err := os.Rename(db.addr, db.addr+".bak"); err != nil {
panic(err)
}
if err := os.WriteFile(db.addr, b, os.ModePerm); err != nil {
panic(err)
}
}
func (db yamlDB) HistoryOf(user IDU) map[IDQ][]History {
result := map[IDQ][]History{}
for k, v := range db.Users[user].History {
result[k] = append([]History{}, v...)
}
for _, tag := range db.Users[user].Tags.Assignments {
for qid, q := range db.Knowledge.Questions {
if _, ok := result[qid]; !ok && q.Tagged(tag) {
result[qid] = []History{}
}
}
}
return result
}
func (db yamlDB) Next(user IDU, q IDQ) time.Time {
history := db.Users[user].History[q]
last := db.lastTS(user, q)
log := make([]int, 0, len(history))
for i := range history {
v := 0
if history[i].Pass {
v = 5
}
log = append(log, v)
}
return Next(last, log)
}
func (db yamlDB) Question(q IDQ) Question {
return db.Knowledge.Questions[q]
}
func (db yamlDB) LastAnswer(user IDU, q IDQ) (IDA, Answer) {
var maxk IDA
var maxv Answer
for k, v := range db.Knowledge.Answers {
if v.Q == q && v.Author == user {
if maxv.TS < v.TS {
maxk = k
maxv = v
}
}
}
return maxk, maxv
}
func (db yamlDB) Answer(a IDA) Answer {
return db.Knowledge.Answers[a]
}
func (db yamlDB) PushAnswer(user IDU, q IDQ, a Renderable, pass bool) error {
uuid := IDA(uuid.New().String())
db.Knowledge.Answers[uuid] = Answer{
Q: q,
A: a,
TS: time.Now().UnixNano(),
Author: user,
}
db.Users[user].History[q] = append(db.Users[user].History[q], History{
A: uuid,
Pass: pass,
TS: db.Knowledge.Answers[uuid].TS,
})
return nil
}
func (db yamlDB) lastTS(user IDU, q IDQ) time.Time {
max := int64(0)
for _, v := range db.Users[user].History[q] {
if v.TS > max {
max = v.TS
}
}
return time.Unix(0, max)
}