wisski-cloud-distillery/internal/component/instances/instances.go
2022-09-19 23:16:56 +02:00

143 lines
3.7 KiB
Go

package instances
import (
"errors"
"github.com/FAU-CDI/wisski-distillery/internal/component"
"github.com/FAU-CDI/wisski-distillery/internal/component/sql"
"github.com/FAU-CDI/wisski-distillery/internal/component/triplestore"
"github.com/FAU-CDI/wisski-distillery/internal/models"
"github.com/tkw1536/goprogram/exit"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
// Instances manages multiple WissKI Instances.
type Instances struct {
component.ComponentBase
TS *triplestore.Triplestore
SQL *sql.SQL
}
func (Instances) Name() string {
return "instances"
}
// ErrWissKINotFound is returned when a WissKI is not found
var ErrWissKINotFound = errors.New("WissKI not found")
var errSQL = exit.Error{
Message: "Unknown SQL Error %s",
ExitCode: exit.ExitGeneric,
}
// WissKI returns the WissKI with the provided slug, if it exists.
// It the WissKI does not exist, returns ErrWissKINotFound.
func (instances *Instances) WissKI(slug string) (i WissKI, err error) {
sql := instances.SQL
if err := sql.WaitQueryTable(); err != nil {
return i, err
}
table, err := sql.QueryTable(false, models.InstanceTable)
if err != nil {
return i, err
}
// find the instance by slug
query := table.Where(&models.Instance{Slug: slug}).Find(&i.Instance)
switch {
case query.Error != nil:
return i, errSQL.WithMessageF(query.Error)
case query.RowsAffected == 0:
return i, ErrWissKINotFound
default:
i.instances = instances
return i, nil
}
}
// Has checks if a WissKI with the provided slug exists inside the database.
// It does not perform any checks on the WissKI itself.
func (instances *Instances) Has(slug string) (ok bool, err error) {
sql := instances.SQL
if err := sql.WaitQueryTable(); err != nil {
return false, err
}
table, err := sql.QueryTable(false, models.InstanceTable)
if err != nil {
return false, err
}
query := table.Select("count(*) > 0").Where("slug = ?", slug).Find(&ok)
if query.Error != nil {
return false, errSQL.WithMessageF(query.Error)
}
return
}
// All returns all instances of the WissKI Distillery in consistent order.
//
// There is no guarantee that this order remains identical between different api releases; however subsequent invocations are guaranteed to return the same order.
func (instances *Instances) All() ([]WissKI, error) {
return instances.find(true, func(table *gorm.DB) *gorm.DB {
return table
})
}
// WissKIs returns the WissKI instances with the provides slugs.
// If a slug does not exist, it is omitted from the result.
func (instances *Instances) WissKIs(slugs ...string) ([]WissKI, error) {
return instances.find(true, func(table *gorm.DB) *gorm.DB {
return table.Where("slug IN ?", slugs)
})
}
// Load is like All, except that when no slugs are provided, it calls All.
func (instances *Instances) Load(slugs ...string) ([]WissKI, error) {
if len(slugs) == 0 {
return instances.All()
}
return instances.WissKIs(slugs...)
}
// find finds instances based on the provided query
func (instances *Instances) find(order bool, query func(table *gorm.DB) *gorm.DB) (results []WissKI, err error) {
sql := instances.SQL
if err := sql.WaitQueryTable(); err != nil {
return nil, err
}
// open the bookkeeping table
table, err := sql.QueryTable(false, models.InstanceTable)
if err != nil {
return nil, err
}
// prepare a query
find := table
if order {
find = find.Order(clause.OrderByColumn{Column: clause.Column{Name: "slug"}, Desc: false})
}
if query != nil {
find = query(find)
}
// fetch bookkeeping instances
var bks []models.Instance
find = find.Find(&bks)
if find.Error != nil {
return nil, errSQL.WithMessageF(find.Error)
}
// make proper instances
results = make([]WissKI, len(bks))
for i, bk := range bks {
results[i].Instance = bk
results[i].instances = instances
}
return results, nil
}