Completed first refactoring with Go generics

This commit is contained in:
andrea 2023-11-18 11:12:07 +01:00
parent 8382cc4222
commit 3cdfa72403
16 changed files with 501 additions and 164 deletions

1
go.mod
View file

@ -15,6 +15,7 @@ require (
github.com/glebarez/go-sqlite v1.21.2 // indirect github.com/glebarez/go-sqlite v1.21.2 // indirect
github.com/glebarez/sqlite v1.9.0 // indirect github.com/glebarez/sqlite v1.9.0 // indirect
github.com/go-yaml/yaml v2.1.0+incompatible // indirect github.com/go-yaml/yaml v2.1.0+incompatible // indirect
github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/kr/pretty v0.2.1 // indirect github.com/kr/pretty v0.2.1 // indirect

3
go.sum
View file

@ -7,6 +7,8 @@ github.com/glebarez/sqlite v1.9.0 h1:Aj6bPA12ZEx5GbSF6XADmCkYXlljPNUY+Zf1EQxynXs
github.com/glebarez/sqlite v1.9.0/go.mod h1:YBYCoyupOao60lzp1MVBLEjZfgkq0tdB1voAQ09K9zw= github.com/glebarez/sqlite v1.9.0/go.mod h1:YBYCoyupOao60lzp1MVBLEjZfgkq0tdB1voAQ09K9zw=
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o= github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d h1:KbPOUXFUDJxwZ04vbmDOc3yuruGvVO+LOa7cVER3yWw=
github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
@ -37,6 +39,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=

View file

@ -1,12 +1,44 @@
package models package models
import (
"crypto/sha256"
"fmt"
"strings"
)
type Participant struct { type Participant struct {
ID string `gorm:"primaryKey"` ID string `csv:"id" gorm:"primaryKey"`
Firstname string Firstname string `csv:"firstname"`
Lastname string Lastname string `csv:"lastname"`
Token uint Token uint `csv:"token"`
Attributes map[string]string Attributes map[string]string
} }
func (p *Participant) String() string {
return fmt.Sprintf("%s %s", p.Lastname, p.Firstname)
}
func (p *Participant) GetID() string {
return p.ID
}
func (p *Participant) SetID(id string) {
p.ID = id
}
func (p *Participant) GetHash() string {
return fmt.Sprintf("%x", sha256.Sum256([]byte(strings.Join(append([]string{p.Lastname, p.Firstname}, p.AttributesToSlice()...), ""))))
}
func (p *Participant) AttributesToSlice() []string {
result := make([]string, len(p.Attributes)*2)
for k, v := range p.Attributes {
result = append(result, k, v)
}
return result
}

5
store/collection.go Normal file
View file

@ -0,0 +1,5 @@
package store
import "git.andreafazzi.eu/andrea/probo/models"
type CollectionStore = Store[*models.Collection]

View file

@ -9,45 +9,46 @@ import (
"git.andreafazzi.eu/andrea/probo/store" "git.andreafazzi.eu/andrea/probo/store"
) )
func NewCollectionFileStore() (*FileStore[*models.Collection, *store.Store[*models.Collection]], error) { type CollectionFileStore = FileStore[*models.Collection, *store.Store[*models.Collection]]
return NewFileStore[*models.Collection](
store.NewStore[*models.Collection](),
filepath.Join(BaseDir, CollectionsDir),
"collection",
".json",
func(s *store.Store[*models.Collection], filepath string, content []byte) (*models.Collection, error) {
collection := new(models.Collection)
err := json.Unmarshal(content, &collection)
if err != nil {
return nil, err
}
c, err := s.Create(collection) var DefaultCollectionDir = filepath.Join(BaseDir, CollectionsDir)
if err != nil {
return nil, err
}
return c, nil func NewCollectionFileStore(config *FileStoreConfig[*models.Collection, *store.CollectionStore]) (*CollectionFileStore, error) {
}, return NewFileStore[*models.Collection](config, store.NewStore[*models.Collection]())
func(s *store.Store[*models.Collection], filePath string, collection *models.Collection) error { }
jsonData, err := json.Marshal(collection)
if err != nil { func DefaultUnmarshalCollectionFunc(s *store.Store[*models.Collection], filepath string, content []byte) (*models.Collection, error) {
return err collection := new(models.Collection)
} err := json.Unmarshal(content, &collection)
if err != nil {
file, err := os.Create(filePath) return nil, err
if err != nil { }
return err
} c, err := s.Create(collection)
if err != nil {
defer file.Close() return nil, err
}
_, err = file.Write(jsonData)
if err != nil { return c, nil
return err }
}
func DefaultMarshalCollectionFunc(s *store.Store[*models.Collection], filePath string, collection *models.Collection) error {
return nil jsonData, err := json.Marshal(collection)
}, if err != nil {
) return err
}
file, err := os.Create(filePath)
if err != nil {
return err
}
defer file.Close()
_, err = file.Write(jsonData)
if err != nil {
return err
}
return nil
} }

View file

@ -48,7 +48,14 @@ func (t *collectionTestSuite) TestCreateCollection() {
}, },
}) })
store, err := NewCollectionFileStore() store, err := NewCollectionFileStore(
&FileStoreConfig[*models.Collection, *store.CollectionStore]{
FilePathConfig: FilePathConfig{"testdata", "collection", ".json"},
IndexDirFunc: DefaultIndexDirFunc[*models.Collection, *store.CollectionStore],
UnmarshalFunc: DefaultUnmarshalCollectionFunc,
MarshalFunc: DefaultMarshalCollectionFunc,
},
)
t.Nil(err) t.Nil(err)
c := new(models.Collection) c := new(models.Collection)

View file

@ -1,6 +1,7 @@
package file package file
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/fs" "io/fs"
@ -12,49 +13,121 @@ import (
"git.andreafazzi.eu/andrea/probo/store" "git.andreafazzi.eu/andrea/probo/store"
) )
type IndexDirFunc[T store.Storable, K Storer[T]] func(s *FileStore[T, K]) error
var ( var (
ErrorMetaHeaderIsNotPresent = errors.New("Meta header was not found in file.") ErrorMetaHeaderIsNotPresent = errors.New("Meta header was not found in file.")
BaseDir = "data" BaseDir = "data"
QuizzesDir = "quizzes" QuizzesDir = "quizzes"
CollectionsDir = "collections" CollectionsDir = "collections"
ParticipantsDir = "participants"
) )
type Storer[T store.Storable] interface { type Storer[T store.Storable] interface {
store.Storer[T] store.Storer[T]
// store.FilterStorer[T]
} }
type FileStore[T store.Storable, K Storer[T]] struct { type FilePathConfig struct {
Storer K
Dir string Dir string
FilePrefix string FilePrefix string
FileSuffix string FileSuffix string
}
MarshalFunc func(K, string, []byte) (T, error) type FileStoreConfig[T store.Storable, K Storer[T]] struct {
UnmarshalFunc func(K, string, T) error FilePathConfig
FilepathFunc func(T, *FilePathConfig) string
UnmarshalFunc func(K, string, []byte) (T, error)
MarshalFunc func(K, string, T) error
IndexDirFunc func(*FileStore[T, K]) error
}
type FileStore[T store.Storable, K Storer[T]] struct {
*FileStoreConfig[T, K]
Storer K
lock sync.RWMutex lock sync.RWMutex
paths map[string]string paths map[string]string
} }
func NewFileStore[T store.Storable, K Storer[T]]( func DefaultJSONUnmarshalFunc[T store.Storable, K Storer[T]](s K, filepath string, content []byte) (T, error) {
storer K, entity := new(T)
dir string, err := json.Unmarshal(content, &entity)
prefix string, if err != nil {
suffix string, return *entity, err
marshalFunc func(K, string, []byte) (T, error), }
unmarshalFunc func(K, string, T) error,
) (*FileStore[T, K], error) { c, err := s.Create(*entity)
if err != nil {
return c, err
}
return c, nil
}
func DefaultJSONMarshalFunc[T store.Storable, K Storer[T]](s K, filePath string, entity T) error {
jsonData, err := json.Marshal(entity)
if err != nil {
return err
}
file, err := os.Create(filePath)
if err != nil {
return err
}
defer file.Close()
_, err = file.Write(jsonData)
if err != nil {
return err
}
return nil
}
func DefaultIndexDirFunc[T store.Storable, K Storer[T]](s *FileStore[T, K]) error {
files, err := os.ReadDir(s.Dir)
if err != nil {
return err
}
entityFiles := make([]fs.DirEntry, 0)
for _, file := range files {
filename := file.Name()
if !file.IsDir() && strings.HasSuffix(filename, s.FileSuffix) {
entityFiles = append(entityFiles, file)
}
}
for _, file := range entityFiles {
filename := file.Name()
fullPath := filepath.Join(s.Dir, filename)
content, err := os.ReadFile(fullPath)
if err != nil {
return err
}
entity, err := s.UnmarshalFunc(s.Storer, fullPath, content)
if err != nil {
return err
}
s.SetPath(entity, fullPath)
}
return nil
}
func NewFileStore[T store.Storable, K Storer[T]](config *FileStoreConfig[T, K], storer K) (*FileStore[T, K], error) {
store := &FileStore[T, K]{ store := &FileStore[T, K]{
Storer: storer, FileStoreConfig: config,
Dir: dir, Storer: storer,
FilePrefix: prefix, paths: make(map[string]string, 0),
FileSuffix: suffix,
MarshalFunc: marshalFunc,
UnmarshalFunc: unmarshalFunc,
paths: make(map[string]string, 0),
} }
err := store.IndexDir() err := store.IndexDir()
@ -72,9 +145,15 @@ func (s *FileStore[T, K]) Create(entity T) (T, error) {
return e, err return e, err
} }
filePath := filepath.Join(s.Dir, fmt.Sprintf("%s_%v%s", s.FilePrefix, e.GetID(), s.FileSuffix)) var filePath string
err = s.UnmarshalFunc(s.Storer, filePath, e) if s.FilepathFunc == nil {
filePath = filepath.Join(s.Dir, fmt.Sprintf("%s_%v%s", s.FilePrefix, e.GetID(), s.FileSuffix))
} else {
filePath = s.FilepathFunc(entity, &s.FilePathConfig)
}
err = s.MarshalFunc(s.Storer, filePath, e)
if err != nil { if err != nil {
return e, err return e, err
} }
@ -90,15 +169,13 @@ func (s *FileStore[T, K]) Update(entity T, id string) (T, error) {
return e, err return e, err
} }
filePath := filepath.Join(s.Dir, fmt.Sprintf("%s_%v%s", s.FilePrefix, e.GetID(), s.FileSuffix)) filePath := s.GetPath(e)
err = s.UnmarshalFunc(s.Storer, filePath, e) err = s.MarshalFunc(s.Storer, filePath, e)
if err != nil { if err != nil {
return e, err return e, err
} }
s.SetPath(e, filePath)
return e, nil return e, nil
} }
@ -125,39 +202,7 @@ func (s *FileStore[T, K]) Delete(id string) (T, error) {
} }
func (s *FileStore[T, K]) IndexDir() error { func (s *FileStore[T, K]) IndexDir() error {
files, err := os.ReadDir(s.Dir) return s.IndexDirFunc(s)
if err != nil {
return err
}
entityFiles := make([]fs.DirEntry, 0)
for _, file := range files {
filename := file.Name()
if !file.IsDir() && strings.HasSuffix(filename, s.FileSuffix) {
entityFiles = append(entityFiles, file)
}
}
for _, file := range entityFiles {
filename := file.Name()
fullPath := filepath.Join(s.Dir, filename)
content, err := os.ReadFile(fullPath)
if err != nil {
return err
}
entity, err := s.MarshalFunc(s.Storer, fullPath, content)
if err != nil {
return err
}
s.SetPath(entity, fullPath)
}
return nil
} }
func (s *FileStore[T, K]) GetPath(entity T) string { func (s *FileStore[T, K]) GetPath(entity T) string {

View file

@ -13,5 +13,6 @@ func TestRunner(t *testing.T) {
t, t,
new(quizTestSuite), new(quizTestSuite),
new(collectionTestSuite), new(collectionTestSuite),
new(participantTestSuite),
) )
} }

51
store/file/participant.go Normal file
View file

@ -0,0 +1,51 @@
package file
import (
"encoding/json"
"os"
"git.andreafazzi.eu/andrea/probo/models"
"git.andreafazzi.eu/andrea/probo/store"
)
type ParticipantFileStore = FileStore[*models.Participant, *store.Store[*models.Participant]]
func NewParticipantFileStore(config *FileStoreConfig[*models.Participant, *store.Store[*models.Participant]]) (*ParticipantFileStore, error) {
return NewFileStore[*models.Participant](config, store.NewStore[*models.Participant]())
}
func DefaultUnmarshalParticipantFunc(s *store.Store[*models.Participant], filepath string, content []byte) (*models.Participant, error) {
participant := new(models.Participant)
err := json.Unmarshal(content, &participant)
if err != nil {
return nil, err
}
c, err := s.Create(participant)
if err != nil {
return nil, err
}
return c, nil
}
func DefaultMarshalParticipantFunc(s *store.Store[*models.Participant], filePath string, participant *models.Participant) error {
jsonData, err := json.Marshal(participant)
if err != nil {
return err
}
file, err := os.Create(filePath)
if err != nil {
return err
}
defer file.Close()
_, err = file.Write(jsonData)
if err != nil {
return err
}
return nil
}

View file

@ -0,0 +1,44 @@
package file
import (
"os"
"git.andreafazzi.eu/andrea/probo/models"
"git.andreafazzi.eu/andrea/probo/store"
"github.com/remogatto/prettytest"
)
type participantTestSuite struct {
prettytest.Suite
}
func (t *participantTestSuite) TestCreate() {
filePathConfig := FilePathConfig{"testdata/participants", "participant", ".json"}
pStore, err := NewParticipantFileStore(
&FileStoreConfig[*models.Participant, *store.ParticipantStore]{
FilePathConfig: filePathConfig,
IndexDirFunc: DefaultIndexDirFunc[*models.Participant, *store.ParticipantStore],
UnmarshalFunc: DefaultJSONUnmarshalFunc[*models.Participant, *store.ParticipantStore],
MarshalFunc: DefaultJSONMarshalFunc[*models.Participant, *store.ParticipantStore],
})
t.Nil(err)
if !t.Failed() {
p, err := pStore.Create(&models.Participant{
Lastname: "Doe",
Firstname: "John",
Attributes: map[string]string{"class": "1 D LIN"},
})
t.Nil(err)
defer os.Remove(pStore.GetPath(p))
if !t.Failed() {
exists, err := os.Stat(pStore.GetPath(p))
t.Nil(err)
t.Not(t.Nil(exists))
}
}
}

View file

@ -6,7 +6,6 @@ import (
"errors" "errors"
"io" "io"
"os" "os"
"path/filepath"
"strings" "strings"
"time" "time"
@ -15,60 +14,59 @@ import (
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
func NewQuizFileStore() (*FileStore[*models.Quiz, *store.QuizStore], error) { type QuizFileStore = FileStore[*models.Quiz, *store.QuizStore]
return NewFileStore[*models.Quiz, *store.QuizStore](
store.NewQuizStore(),
filepath.Join(BaseDir, QuizzesDir),
"quiz",
".md",
func(s *store.QuizStore, filepath string, content []byte) (*models.Quiz, error) {
quiz, meta, err := models.MarkdownToQuiz(string(content))
if err != nil {
return nil, err
}
var errQuizAlreadyPresent *store.ErrQuizAlreadyPresent func NewQuizFileStore(config *FileStoreConfig[*models.Quiz, *store.QuizStore]) (*QuizFileStore, error) {
return NewFileStore[*models.Quiz, *store.QuizStore](config, store.NewQuizStore())
}
q, err := s.Create(quiz) func DefaultUnmarshalQuizFunc(s *store.QuizStore, filepath string, content []byte) (*models.Quiz, error) {
if err != nil && !errors.As(err, &errQuizAlreadyPresent) { quiz, meta, err := models.MarkdownToQuiz(string(content))
return nil, err if err != nil {
} return nil, err
}
if meta == nil { var errQuizAlreadyPresent *store.ErrQuizAlreadyPresent
writeQuizHeader(filepath, &models.Meta{
ID: q.ID,
CreatedAt: time.Now(),
})
}
return q, nil q, err := s.Create(quiz)
}, if err != nil && !errors.As(err, &errQuizAlreadyPresent) {
func(s *store.QuizStore, filePath string, quiz *models.Quiz) error { return nil, err
markdown, err := models.QuizToMarkdown(quiz) }
if err != nil {
return err
}
file, err := os.Create(filePath) if meta == nil {
if err != nil { writeQuizHeader(filepath, &models.Meta{
return err ID: q.ID,
} CreatedAt: time.Now(),
})
}
defer file.Close() return q, nil
}
markdownWithMetaHeader, err := addMetaHeaderToMarkdown(markdown, &quiz.Meta) func DefaultMarshalQuizFunc(s *store.QuizStore, filePath string, quiz *models.Quiz) error {
if err != nil { markdown, err := models.QuizToMarkdown(quiz)
return err if err != nil {
} return err
}
_, err = file.Write([]byte(markdownWithMetaHeader)) file, err := os.Create(filePath)
if err != nil { if err != nil {
return err return err
} }
return nil defer file.Close()
},
) markdownWithMetaHeader, err := addMetaHeaderToMarkdown(markdown, &quiz.Meta)
if err != nil {
return err
}
_, err = file.Write([]byte(markdownWithMetaHeader))
if err != nil {
return err
}
return nil
} }
func writeQuizHeader(path string, meta *models.Meta) (*models.Meta, error) { func writeQuizHeader(path string, meta *models.Meta) (*models.Meta, error) {
@ -214,3 +212,57 @@ func removeQuizHeader(path string) (*models.Meta, error) {
return &meta, nil return &meta, nil
} }
// filepath.Join(BaseDir, QuizzesDir),
// "quiz",
// ".md",
// DefaultIndexDirFunc,
// nil,
// func(s *store.QuizStore, filepath string, content []byte) (*models.Quiz, error) {
// quiz, meta, err := models.MarkdownToQuiz(string(content))
// if err != nil {
// return nil, err
// }
// var errQuizAlreadyPresent *store.ErrQuizAlreadyPresent
// q, err := s.Create(quiz)
// if err != nil && !errors.As(err, &errQuizAlreadyPresent) {
// return nil, err
// }
// if meta == nil {
// writeQuizHeader(filepath, &models.Meta{
// ID: q.ID,
// CreatedAt: time.Now(),
// })
// }
// return q, nil
// },
// func(s *store.QuizStore, filePath string, quiz *models.Quiz) error {
// markdown, err := models.QuizToMarkdown(quiz)
// if err != nil {
// return err
// }
// file, err := os.Create(filePath)
// if err != nil {
// return err
// }
// defer file.Close()
// markdownWithMetaHeader, err := addMetaHeaderToMarkdown(markdown, &quiz.Meta)
// if err != nil {
// return err
// }
// _, err = file.Write([]byte(markdownWithMetaHeader))
// if err != nil {
// return err
// }
// return nil
// },
// )

View file

@ -6,6 +6,7 @@ import (
"path/filepath" "path/filepath"
"git.andreafazzi.eu/andrea/probo/models" "git.andreafazzi.eu/andrea/probo/models"
"git.andreafazzi.eu/andrea/probo/store"
"github.com/remogatto/prettytest" "github.com/remogatto/prettytest"
) )
@ -13,12 +14,16 @@ type quizTestSuite struct {
prettytest.Suite prettytest.Suite
} }
func (t *quizTestSuite) BeforeAll() {
BaseDir = "testdata"
}
func (t *quizTestSuite) TestReadAll() { func (t *quizTestSuite) TestReadAll() {
store, err := NewQuizFileStore() filePathConfig := FilePathConfig{"testdata/quizzes", "quiz", ".md"}
store, err := NewQuizFileStore(
&FileStoreConfig[*models.Quiz, *store.QuizStore]{
FilePathConfig: filePathConfig,
IndexDirFunc: DefaultIndexDirFunc[*models.Quiz, *store.QuizStore],
UnmarshalFunc: DefaultUnmarshalQuizFunc,
MarshalFunc: DefaultMarshalQuizFunc,
},
)
t.Nil(err) t.Nil(err)
if !t.Failed() { if !t.Failed() {
@ -36,7 +41,15 @@ func (t *quizTestSuite) TestReadAll() {
} }
func (t *quizTestSuite) TestCreate() { func (t *quizTestSuite) TestCreate() {
store, err := NewQuizFileStore() filePathConfig := FilePathConfig{"testdata/quizzes", "quiz", ".md"}
store, err := NewQuizFileStore(
&FileStoreConfig[*models.Quiz, *store.QuizStore]{
FilePathConfig: filePathConfig,
IndexDirFunc: DefaultIndexDirFunc[*models.Quiz, *store.QuizStore],
UnmarshalFunc: DefaultUnmarshalQuizFunc,
MarshalFunc: DefaultMarshalQuizFunc,
},
)
t.Nil(err) t.Nil(err)
if !t.Failed() { if !t.Failed() {
@ -90,7 +103,15 @@ func (t *quizTestSuite) TestCreate() {
} }
func (t *quizTestSuite) TestDelete() { func (t *quizTestSuite) TestDelete() {
store, err := NewQuizFileStore() filePathConfig := FilePathConfig{"testdata/quizzes", "quiz", ".md"}
store, err := NewQuizFileStore(
&FileStoreConfig[*models.Quiz, *store.QuizStore]{
FilePathConfig: filePathConfig,
IndexDirFunc: DefaultIndexDirFunc[*models.Quiz, *store.QuizStore],
UnmarshalFunc: DefaultUnmarshalQuizFunc,
MarshalFunc: DefaultMarshalQuizFunc,
},
)
t.Nil(err) t.Nil(err)
if !t.Failed() { if !t.Failed() {
@ -121,7 +142,15 @@ func (t *quizTestSuite) TestDelete() {
} }
func (t *quizTestSuite) TestUpdate() { func (t *quizTestSuite) TestUpdate() {
store, err := NewQuizFileStore() filePathConfig := FilePathConfig{"testdata/quizzes", "quiz", ".md"}
store, err := NewQuizFileStore(
&FileStoreConfig[*models.Quiz, *store.QuizStore]{
FilePathConfig: filePathConfig,
IndexDirFunc: DefaultIndexDirFunc[*models.Quiz, *store.QuizStore],
UnmarshalFunc: DefaultUnmarshalQuizFunc,
MarshalFunc: DefaultMarshalQuizFunc,
},
)
t.Nil(err) t.Nil(err)
if !t.Failed() { if !t.Failed() {
@ -161,7 +190,15 @@ func (t *quizTestSuite) TestUpdate() {
} }
func (t *quizTestSuite) TestAutowriteHeader() { func (t *quizTestSuite) TestAutowriteHeader() {
store, err := NewQuizFileStore() filePathConfig := FilePathConfig{"testdata/quizzes", "quiz", ".md"}
store, err := NewQuizFileStore(
&FileStoreConfig[*models.Quiz, *store.QuizStore]{
FilePathConfig: filePathConfig,
IndexDirFunc: DefaultIndexDirFunc[*models.Quiz, *store.QuizStore],
UnmarshalFunc: DefaultUnmarshalQuizFunc,
MarshalFunc: DefaultMarshalQuizFunc,
},
)
t.Nil(err) t.Nil(err)
if !t.Failed() { if !t.Failed() {

View file

@ -1,6 +1,6 @@
--- ---
id: 57ebde24-51a0-421e-a641-4a5c198473c3 id: edadaa90-802f-4a74-83cc-4b4cb5192f28
created_at: 2023-11-13T21:02:55.786449849+01:00 created_at: 2023-11-17T16:50:38.479350601+01:00
updated_at: 0001-01-01T00:00:00Z updated_at: 0001-01-01T00:00:00Z
--- ---
This quiz is initially without metadata. This quiz is initially without metadata.

5
store/participant.go Normal file
View file

@ -0,0 +1,5 @@
package store
import "git.andreafazzi.eu/andrea/probo/models"
type ParticipantStore = Store[*models.Participant]

52
store/participant_test.go Normal file
View file

@ -0,0 +1,52 @@
package store
import (
"git.andreafazzi.eu/andrea/probo/models"
"github.com/remogatto/prettytest"
)
type participantTestSuite struct {
prettytest.Suite
}
func (t *participantTestSuite) TestCreate() {
store := NewStore[*models.Participant]()
p_1, err := store.Create(&models.Participant{
Lastname: "Doe",
Firstname: "John",
})
t.Nil(err)
p_2, err := store.Create(&models.Participant{
Lastname: "Doe",
Firstname: "John",
Attributes: map[string]string{"class": "1 D LIN"},
})
t.Nil(err)
t.False(p_1.GetHash() == p_2.GetHash())
}
func (t *participantTestSuite) TestUpdate() {
store := NewStore[*models.Participant]()
p, err := store.Create(&models.Participant{
Lastname: "Doe",
Firstname: "John",
})
t.Nil(err)
updatedP, err := store.Update(&models.Participant{
Lastname: "Doe",
Firstname: "John",
Attributes: map[string]string{"class": "1 D LIN"},
}, p.ID)
t.Nil(err)
t.False(p.GetHash() == updatedP.GetHash())
}

View file

@ -11,5 +11,6 @@ func TestRunner(t *testing.T) {
t, t,
new(quizTestSuite), new(quizTestSuite),
new(collectionTestSuite), new(collectionTestSuite),
new(participantTestSuite),
) )
} }