Files
Foundry-Scrapping-API/internal/foundry/models/db/world.go

183 lines
5.5 KiB
Go

package db
import (
"context"
"database/sql"
"errors"
"fmt"
"time"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type World struct {
ID string
Title string
Description string
Version string
System string
Background string
JoinTheme string
CoreVersion string
SystemVersion string
LastPlayed string
Playtime int
Availability int
NextSession time.Time
Socket bool
Protected bool
Exclusive bool
PersistentStorage bool
Locked bool
Owned bool
HasStorage bool
Compatibility Compatibility
Relationships Relationships
Tags []string
Scripts []string
Esmodules []string
Authors []*Author
Media []*Media
Styles []*Style
Languages []*Language
Packs []*Pack
PackFolders []*Folder
}
func (w *World) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO world (%[1]s, id, title, description, version, system, background, join_theme,
core_version, system_version, last_played, playtime, availability, next_session, socket,
protected, exclusive_, persistent_storage, locked, owned, has_storage)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21)
ON CONFLICT(id) DO UPDATE SET
%[1]s = EXCLUDED.%[1]s,
updated_at = datetime('now')
RETURNING (created_at == updated_at) AS is_inserted`,
data.fieldName)
}
func (w *World) InsertObjects(tx *sqlx.Tx) error {
relId := InsertId[string]{id: w.ID, fieldName: "world_id"}
group, ctx := errgroup.WithContext(context.Background())
InsertWithCtxParallel(group, ctx, tx, w.Compatibility, relId)
InsertWithCtxParallel(group, ctx, tx, w.Relationships, relId)
esModulesRelId := &InsertId[string]{id: w.ID, fieldName: "world_id", tableName: "es_modules"}
InsertSimpleSliceParallel(group, tx, w.Esmodules, esModulesRelId)
scriptRelId := &InsertId[string]{id: w.ID, fieldName: "world_id", tableName: "scripts"}
InsertSimpleSliceParallel(group, tx, w.Scripts, scriptRelId)
tagsRelId := &InsertId[string]{id: w.ID, fieldName: "world_id", tableName: "tags"}
InsertSimpleSliceParallel(group, tx, w.Tags, tagsRelId)
InsertSliceParallel(group, tx, w.Authors, relId)
InsertSliceParallel(group, tx, w.Media, relId)
InsertSliceParallel(group, tx, w.Styles, relId)
InsertSliceParallel(group, tx, w.Languages, relId)
InsertSliceParallel(group, tx, w.Packs, relId)
InsertSliceParallel(group, tx, w.PackFolders, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (w *World) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, w.ID, w.Title, w.Description, w.Version, w.System, w.Background, w.JoinTheme,
w.CoreVersion, w.SystemVersion, w.LastPlayed, w.Playtime, w.Availability, w.NextSession, w.Socket,
w.Protected, w.Exclusive, w.PersistentStorage, w.Locked, w.Owned, w.HasStorage}
var isInserted bool
err := tx.QueryRowx(data.query, args...).Scan(&isInserted)
if err != nil {
return err
}
if isInserted {
return w.InsertObjects(tx)
}
return nil
}
func (w *World) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, w.ID, w.Title, w.Description, w.Version, w.System, w.Background, w.JoinTheme,
w.CoreVersion, w.SystemVersion, w.LastPlayed, w.Playtime, w.Availability, w.NextSession, w.Socket,
w.Protected, w.Exclusive, w.PersistentStorage, w.Locked, w.Owned, w.HasStorage}
var isInserted bool
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&isInserted)
if err != nil {
return err
}
if isInserted {
return w.InsertObjects(tx)
}
return nil
}
func GetNotStartedWorlds(db *sqlx.DB) ([]string, error) {
const query = `
SELECT id FROM world WHERE game_id IS NULL`
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var worldNames []string
err := db.SelectContext(ctx, &worldNames, query)
if err != nil {
return nil, err
}
return worldNames, nil
}
func IsWorldInserted(db *sqlx.DB, worldName string) (bool, error) {
const query = `
SELECT EXISTS(SELECT 1 FROM world WHERE id = $1 AND game_id IS NOT NULL)`
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var exist bool
err := db.GetContext(ctx, &exist, query, worldName)
if err != nil {
return false, err
}
return exist, nil
}
func GetWorld(db *sqlx.DB, worldName string) (*World, error) {
const query = `
SELECT id, title, description, version, system, background, join_theme, core_version, system_version,
last_played, playtime, availability, next_session, socket, protected, exclusive_, persistent_storage,
locked, owned, has_storage
FROM world WHERE id = $1`
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var world World
err := db.QueryRowxContext(ctx, query, worldName).Scan(
&world.ID, &world.Title, &world.Description, &world.Version, &world.System, &world.Background, &world.JoinTheme,
&world.CoreVersion, &world.SystemVersion, &world.LastPlayed, &world.Playtime, &world.Availability, &world.NextSession,
&world.Socket, &world.Protected, &world.Exclusive, &world.PersistentStorage, &world.Locked, &world.Owned, &world.HasStorage,
)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return nil, err
}
return &world, nil
}