finish setup data insertion, add world insertion

This commit is contained in:
lbenedar
2026-04-22 18:18:43 +03:00
parent 21abe68858
commit f46ff8333e
66 changed files with 2257 additions and 676 deletions

View File

@@ -7,6 +7,10 @@ DROP TABLE IF EXISTS author;
DROP TABLE IF EXISTS es_modules; DROP TABLE IF EXISTS es_modules;
DROP TABLE IF EXISTS scripts; DROP TABLE IF EXISTS scripts;
DROP TABLE IF EXISTS tags; DROP TABLE IF EXISTS tags;
DROP TABLE IF EXISTS relationships_systems;
DROP TABLE IF EXISTS relationships_requires;
DROP TABLE IF EXISTS relationships_recommends;
DROP TABLE IF EXISTS relationships_conflicts;
DROP TABLE IF EXISTS relationships; DROP TABLE IF EXISTS relationships;
DROP TABLE IF EXISTS compatibility; DROP TABLE IF EXISTS compatibility;
DROP TABLE IF EXISTS world; DROP TABLE IF EXISTS world;

View File

@@ -171,9 +171,9 @@ CREATE TABLE IF NOT EXISTS relationships (
); );
CREATE TABLE IF NOT EXISTS relationships_systems ( CREATE TABLE IF NOT EXISTS relationships_systems (
id TEXT PRIMARY KEY, id INTEGER PRIMARY KEY AUTOINCREMENT,
relationships_type VARCHAR(32) NOT NULL, key_ TEXT NOT NULL,
type TEXT NOT NULL, type TEXT NOT NULL,
manifest TEXT NOT NULL, manifest TEXT NOT NULL,
@@ -182,9 +182,9 @@ CREATE TABLE IF NOT EXISTS relationships_systems (
); );
CREATE TABLE IF NOT EXISTS relationships_requires ( CREATE TABLE IF NOT EXISTS relationships_requires (
id TEXT PRIMARY KEY, id INTEGER PRIMARY KEY AUTOINCREMENT,
relationships_type VARCHAR(32) NOT NULL, key_ INTEGER NOT NULL,
type TEXT NOT NULL, type TEXT NOT NULL,
manifest TEXT NOT NULL, manifest TEXT NOT NULL,
@@ -193,9 +193,9 @@ CREATE TABLE IF NOT EXISTS relationships_requires (
); );
CREATE TABLE IF NOT EXISTS relationships_recommends ( CREATE TABLE IF NOT EXISTS relationships_recommends (
id TEXT PRIMARY KEY, id INTEGER PRIMARY KEY AUTOINCREMENT,
relationships_type VARCHAR(32) NOT NULL, key_ INTEGER NOT NULL,
type TEXT NOT NULL, type TEXT NOT NULL,
manifest TEXT NOT NULL, manifest TEXT NOT NULL,
@@ -204,9 +204,9 @@ CREATE TABLE IF NOT EXISTS relationships_recommends (
); );
CREATE TABLE IF NOT EXISTS relationships_conflicts ( CREATE TABLE IF NOT EXISTS relationships_conflicts (
id TEXT PRIMARY KEY, id INTEGER PRIMARY KEY AUTOINCREMENT,
relationships_type VARCHAR(32) NOT NULL, key_ INTEGER NOT NULL,
type TEXT NOT NULL, type TEXT NOT NULL,
manifest TEXT NOT NULL, manifest TEXT NOT NULL,
@@ -222,17 +222,14 @@ CREATE TABLE IF NOT EXISTS compatibility (
maximum VARCHAR(64) NOT NULL, maximum VARCHAR(64) NOT NULL,
module_id TEXT UNIQUE, module_id TEXT UNIQUE,
FOREIGN KEY (module_id) REFERENCES module(id) ON DELETE CASCADE, FOREIGN KEY (module_id) REFERENCES module(id) ON DELETE CASCADE
relationships_systems_id TEXT UNIQUE,
FOREIGN KEY (relationships_systems_id) REFERENCES relationships_systems(id) ON DELETE CASCADE
relationships_requires_id TEXT UNIQUE,
FOREIGN KEY (relationships_requires_id) REFERENCES relationships_requires(id) ON DELETE CASCADE
relationships_recommends_id TEXT UNIQUE,
FOREIGN KEY (relationships_recommends_id) REFERENCES relationships_recommends(id) ON DELETE CASCADE
relationships_conflicts_id TEXT UNIQUE,
FOREIGN KEY (relationships_conflicts_id) REFERENCES relationships_conflicts(id) ON DELETE CASCADE
); );
ALTER TABLE compatibility ADD COLUMN relationships_systems_id TEXT REFERENCES relationships_systems(id) ON DELETE CASCADE;
ALTER TABLE compatibility ADD COLUMN relationships_requires_id TEXT REFERENCES relationships_requires(id) ON DELETE CASCADE;
ALTER TABLE compatibility ADD COLUMN relationships_recommends_id TEXT REFERENCES relationships_recommends(id) ON DELETE CASCADE;
ALTER TABLE compatibility ADD COLUMN relationships_conflicts_id TEXT REFERENCES relationships_conflicts(id) ON DELETE CASCADE;
CREATE TABLE IF NOT EXISTS scripts ( CREATE TABLE IF NOT EXISTS scripts (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -304,8 +301,9 @@ CREATE TABLE IF NOT EXISTS language (
); );
CREATE TABLE IF NOT EXISTS pack ( CREATE TABLE IF NOT EXISTS pack (
id TEXT PRIMARY KEY, id INTEGER PRIMARY KEY,
key_ VARCHAR(128) NOT NULL,
name VARCHAR(128) NOT NULL, name VARCHAR(128) NOT NULL,
label VARCHAR(128) NOT NULL, label VARCHAR(128) NOT NULL,
banner VARCHAR(128) NOT NULL, banner VARCHAR(128) NOT NULL,
@@ -326,7 +324,7 @@ CREATE TABLE IF NOT EXISTS ownership (
trusted VARCHAR(128) NOT NULL, trusted VARCHAR(128) NOT NULL,
assistant VARCHAR(128) NOT NULL, assistant VARCHAR(128) NOT NULL,
pack_id TEXT UNIQUE, pack_id INTEGER UNIQUE,
FOREIGN KEY (pack_id) REFERENCES pack(id) ON DELETE CASCADE FOREIGN KEY (pack_id) REFERENCES pack(id) ON DELETE CASCADE
); );
@@ -338,7 +336,7 @@ CREATE TABLE IF NOT EXISTS index_ (
name VARCHAR(128) NOT NULL, name VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL, type VARCHAR(128) NOT NULL,
pack_id TEXT, pack_id INTEGER,
FOREIGN KEY (pack_id) REFERENCES pack(id) ON DELETE CASCADE FOREIGN KEY (pack_id) REFERENCES pack(id) ON DELETE CASCADE
); );
@@ -351,7 +349,7 @@ CREATE TABLE IF NOT EXISTS pack_folder (
type VARCHAR(128) NOT NULL, type VARCHAR(128) NOT NULL,
sort INTEGER NOT NULL, sort INTEGER NOT NULL,
pack_id TEXT, pack_id INTEGER,
FOREIGN KEY (pack_id) REFERENCES pack(id) ON DELETE CASCADE FOREIGN KEY (pack_id) REFERENCES pack(id) ON DELETE CASCADE
); );
@@ -363,15 +361,16 @@ CREATE TABLE IF NOT EXISTS folder (
color VARCHAR(128) NOT NULL, color VARCHAR(128) NOT NULL,
folder_id INTEGER, folder_id INTEGER,
FOREIGN KEY (folder_id) REFERENCES folder(id) ON DELETE CASCADE, FOREIGN KEY (folder_id) REFERENCES folder(id) ON DELETE CASCADE
module_id TEXT,
FOREIGN KEY (module_id) REFERENCES module(id) ON DELETE CASCADE
); );
ALTER TABLE folder ADD COLUMN module_id TEXT REFERENCES module(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_folder_module_id ON folder(module_id);
CREATE TABLE IF NOT EXISTS folder_packs ( CREATE TABLE IF NOT EXISTS folder_packs (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
packs VARCHAR(128) NOT NULL, value VARCHAR(128) NOT NULL,
folder_id INTEGER, folder_id INTEGER,
FOREIGN KEY (folder_id) REFERENCES folder(id) ON DELETE CASCADE FOREIGN KEY (folder_id) REFERENCES folder(id) ON DELETE CASCADE
@@ -390,9 +389,9 @@ CREATE TABLE IF NOT EXISTS news (
); );
CREATE TABLE IF NOT EXISTS package_warnings ( CREATE TABLE IF NOT EXISTS package_warnings (
id TEXT PRIMARY KEY, id INTEGER PRIMARY KEY AUTOINCREMENT,
key_ VARCHAR(128) NOT NULL, key_ TEXT NOT NULL,
setup_id INTEGER, setup_id INTEGER,
FOREIGN KEY (setup_id) REFERENCES setup(id) ON DELETE CASCADE FOREIGN KEY (setup_id) REFERENCES setup(id) ON DELETE CASCADE
@@ -405,7 +404,7 @@ CREATE TABLE IF NOT EXISTS package_warnings_data (
manifest VARCHAR(128) NOT NULL, manifest VARCHAR(128) NOT NULL,
reinstallable BOOLEAN NOT NULL, reinstallable BOOLEAN NOT NULL,
package_warnings_id TEXT, package_warnings_id INTEGER,
FOREIGN KEY (package_warnings_id) REFERENCES package_warnings(id) ON DELETE CASCADE FOREIGN KEY (package_warnings_id) REFERENCES package_warnings(id) ON DELETE CASCADE
); );
@@ -454,9 +453,12 @@ CREATE TABLE IF NOT EXISTS system (
FOREIGN KEY (setup_id) REFERENCES setup(id) ON DELETE CASCADE FOREIGN KEY (setup_id) REFERENCES setup(id) ON DELETE CASCADE
); );
ALTER TABLE compatibility ADD COLUMN system_id TEXT UNIQUE REFERENCES system(id); ALTER TABLE compatibility ADD COLUMN system_id TEXT REFERENCES system(id) ON DELETE CASCADE;
ALTER TABLE relationships ADD COLUMN system_id TEXT UNIQUE REFERENCES system(id); CREATE UNIQUE INDEX idx_compatibility_system_id ON compatibility(system_id);
ALTER TABLE document_types ADD COLUMN system_id TEXT UNIQUE REFERENCES system(id); ALTER TABLE relationships ADD COLUMN system_id TEXT REFERENCES system(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_relationships_system_id ON relationships(system_id);
ALTER TABLE document_types ADD COLUMN system_id TEXT REFERENCES system(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_document_types_system_id ON document_types(system_id);
CREATE TABLE IF NOT EXISTS grid ( CREATE TABLE IF NOT EXISTS grid (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -475,15 +477,15 @@ CREATE TABLE IF NOT EXISTS grid (
FOREIGN KEY (system_id) REFERENCES system(id) ON DELETE CASCADE FOREIGN KEY (system_id) REFERENCES system(id) ON DELETE CASCADE
); );
ALTER TABLE es_modules ADD COLUMN system_id TEXT REFERENCES system(id); ALTER TABLE es_modules ADD COLUMN system_id TEXT REFERENCES system(id) ON DELETE CASCADE;
ALTER TABLE scripts ADD COLUMN system_id TEXT REFERENCES system(id); ALTER TABLE scripts ADD COLUMN system_id TEXT REFERENCES system(id) ON DELETE CASCADE;
ALTER TABLE tags ADD COLUMN system_id TEXT REFERENCES system(id); ALTER TABLE tags ADD COLUMN system_id TEXT REFERENCES system(id) ON DELETE CASCADE;
ALTER TABLE author ADD COLUMN system_id TEXT REFERENCES system(id); ALTER TABLE author ADD COLUMN system_id TEXT REFERENCES system(id) ON DELETE CASCADE;
ALTER TABLE media ADD COLUMN system_id TEXT REFERENCES system(id); ALTER TABLE media ADD COLUMN system_id TEXT REFERENCES system(id) ON DELETE CASCADE;
ALTER TABLE pack ADD COLUMN system_id TEXT REFERENCES system(id); ALTER TABLE pack ADD COLUMN system_id TEXT REFERENCES system(id) ON DELETE CASCADE;
ALTER TABLE style ADD COLUMN system_id TEXT REFERENCES system(id); ALTER TABLE style ADD COLUMN system_id TEXT REFERENCES system(id) ON DELETE CASCADE;
ALTER TABLE language ADD COLUMN system_id TEXT REFERENCES system(id); ALTER TABLE language ADD COLUMN system_id TEXT REFERENCES system(id) ON DELETE CASCADE;
ALTER TABLE folder ADD COLUMN system_id TEXT REFERENCES system(id); ALTER TABLE folder ADD COLUMN system_id TEXT REFERENCES system(id) ON DELETE CASCADE;
CREATE TABLE IF NOT EXISTS world ( CREATE TABLE IF NOT EXISTS world (
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
@@ -512,15 +514,17 @@ CREATE TABLE IF NOT EXISTS world (
FOREIGN KEY (setup_id) REFERENCES setup(id) ON DELETE CASCADE FOREIGN KEY (setup_id) REFERENCES setup(id) ON DELETE CASCADE
); );
ALTER TABLE compatibility ADD COLUMN world_id TEXT UNIQUE REFERENCES world(id); ALTER TABLE compatibility ADD COLUMN world_id TEXT REFERENCES world(id) ON DELETE CASCADE;
ALTER TABLE relationships ADD COLUMN world_id TEXT UNIQUE REFERENCES world(id); CREATE UNIQUE INDEX idx_compatibility_world_id ON compatibility(world_id);
ALTER TABLE relationships ADD COLUMN world_id TEXT REFERENCES world(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_relationships_world_id ON relationships(world_id);
ALTER TABLE tags ADD COLUMN world_id TEXT REFERENCES world(id); ALTER TABLE tags ADD COLUMN world_id TEXT REFERENCES world(id) ON DELETE CASCADE;
ALTER TABLE scripts ADD COLUMN world_id TEXT REFERENCES world(id); ALTER TABLE scripts ADD COLUMN world_id TEXT REFERENCES world(id) ON DELETE CASCADE;
ALTER TABLE es_modules ADD COLUMN world_id TEXT REFERENCES world(id); ALTER TABLE es_modules ADD COLUMN world_id TEXT REFERENCES world(id) ON DELETE CASCADE;
ALTER TABLE author ADD COLUMN world_id TEXT REFERENCES world(id); ALTER TABLE author ADD COLUMN world_id TEXT REFERENCES world(id) ON DELETE CASCADE;
ALTER TABLE media ADD COLUMN world_id TEXT REFERENCES world(id); ALTER TABLE media ADD COLUMN world_id TEXT REFERENCES world(id) ON DELETE CASCADE;
ALTER TABLE style ADD COLUMN world_id TEXT REFERENCES world(id); ALTER TABLE style ADD COLUMN world_id TEXT REFERENCES world(id) ON DELETE CASCADE;
ALTER TABLE language ADD COLUMN world_id TEXT REFERENCES world(id); ALTER TABLE language ADD COLUMN world_id TEXT REFERENCES world(id) ON DELETE CASCADE;
ALTER TABLE pack ADD COLUMN world_id TEXT REFERENCES world(id); ALTER TABLE pack ADD COLUMN world_id TEXT REFERENCES world(id) ON DELETE CASCADE;
ALTER TABLE folder ADD COLUMN world_id TEXT REFERENCES world(id); ALTER TABLE folder ADD COLUMN world_id TEXT REFERENCES world(id) ON DELETE CASCADE;

View File

@@ -361,10 +361,6 @@ CREATE TABLE IF NOT EXISTS active_users (
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
); );
CREATE TABLE IF NOT EXISTS item ( CREATE TABLE IF NOT EXISTS item (
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
@@ -473,7 +469,7 @@ CREATE TABLE IF NOT EXISTS combatant (
); );
CREATE TABLE IF NOT EXISTS stats ( CREATE TABLE IF NOT EXISTS stats (
id TEXT PRIMARY KEY, id INTEGER PRIMARY KEY AUTOINCREMENT,
core_version VARCHAR(128) NOT NULL, core_version VARCHAR(128) NOT NULL,
system_id VARCHAR(128) NOT NULL, system_id VARCHAR(128) NOT NULL,
@@ -514,7 +510,7 @@ CREATE TABLE IF NOT EXISTS stats (
); );
CREATE TABLE IF NOT EXISTS speaker ( CREATE TABLE IF NOT EXISTS speaker (
id TEXT PRIMARY KEY, id INTEGER PRIMARY KEY AUTOINCREMENT,
scene VARCHAR(128) NOT NULL, scene VARCHAR(128) NOT NULL,
actor VARCHAR(128) NOT NULL, actor VARCHAR(128) NOT NULL,
@@ -578,7 +574,7 @@ CREATE TABLE IF NOT EXISTS face (
CREATE TABLE IF NOT EXISTS message_whisper ( CREATE TABLE IF NOT EXISTS message_whisper (
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
whisper VARCHAR(128) NOT NULL, value VARCHAR(128) NOT NULL,
message_id TEXT, message_id TEXT,
FOREIGN KEY (message_id) REFERENCES message(id) ON DELETE CASCADE FOREIGN KEY (message_id) REFERENCES message(id) ON DELETE CASCADE
@@ -587,7 +583,7 @@ CREATE TABLE IF NOT EXISTS message_whisper (
CREATE TABLE IF NOT EXISTS message_rolls ( CREATE TABLE IF NOT EXISTS message_rolls (
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
rolls VARCHAR(128) NOT NULL, value VARCHAR(128) NOT NULL,
message_id TEXT, message_id TEXT,
FOREIGN KEY (message_id) REFERENCES message(id) ON DELETE CASCADE FOREIGN KEY (message_id) REFERENCES message(id) ON DELETE CASCADE
@@ -654,8 +650,6 @@ CREATE TABLE IF NOT EXISTS ownership_string (
FOREIGN KEY (actor_id) REFERENCES actor(id) ON DELETE CASCADE FOREIGN KEY (actor_id) REFERENCES actor(id) ON DELETE CASCADE
); );
CREATE TABLE IF NOT EXISTS system_update ( CREATE TABLE IF NOT EXISTS system_update (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,

View File

@@ -10,6 +10,6 @@ type Actor struct {
Sort int Sort int
PrototypeToken Token PrototypeToken Token
Stats Stats Stats Stats
Items []Item Items []*Item
Ownership []OwnershipString Ownership []OwnershipString
} }

View File

@@ -1,5 +1,11 @@
package db package db
import (
"context"
"github.com/jmoiron/sqlx"
)
type Addresses struct { type Addresses struct {
ID uint ID uint
@@ -7,3 +13,40 @@ type Addresses struct {
Remote string Remote string
RemoteIsAccessible bool RemoteIsAccessible bool
} }
func (a *Addresses) Query(data *InsertId[uint]) {
data.query = `
INSERT INTO addresses (game_id, local, remote, remote_is_accessible)
VALUES ($1, $2, $3, $4)
RETURNING id`
}
func (a *Addresses) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, a.Local, a.Remote, a.RemoteIsAccessible}
err := tx.QueryRowx(data.query, args...).Scan(&a.ID)
if err != nil {
return err
}
return nil
}
func (a *Addresses) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, a.Local, a.Remote, a.RemoteIsAccessible}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&a.ID)
if err != nil {
return err
}
return nil
}

View File

@@ -31,7 +31,7 @@ func (a *Author) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
args := []any{data.id, a.Name, a.URL, a.Email, a.Discord} args := []any{data.id, a.Name, a.URL, a.Email, a.Discord}
err := tx.QueryRow(data.query, args...).Scan(&a.ID) err := tx.QueryRowx(data.query, args...).Scan(&a.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -46,7 +46,7 @@ func (a *Author) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[stri
args := []any{data.id, a.Name, a.URL, a.Email, a.Discord} args := []any{data.id, a.Name, a.URL, a.Email, a.Discord}
err := tx.QueryRowContext(ctx, data.query, args...).Scan(&a.ID) err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&a.ID)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -1,5 +1,14 @@
package db package db
import (
"context"
"database/sql"
"errors"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type CardDeck struct { type CardDeck struct {
ID string ID string
@@ -15,7 +24,58 @@ type CardDeck struct {
DisplayCount bool DisplayCount bool
Stats Stats Stats Stats
Ownership Ownership Ownership Ownership
Cards []Card Cards []*Card
}
func (c *CardDeck) Query(data *InsertId[uint]) {
data.query = `
INSERT INTO card_deck (game_id, id, name, type, description, img, folder, width, height, rotation, sort, display_count)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`
}
func (c *CardDeck) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[string]{id: c.ID, fieldName: "card_deck_id"}
InsertWithCtxParallel(group, ctx, tx, c.Stats, relId)
InsertWithCtxParallel(group, ctx, tx, c.Ownership, relId)
InsertSliceParallel(group, tx, c.Cards, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (c *CardDeck) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, c.ID, c.Name, c.Type, c.Description, c.Img, c.Folder, c.Width, c.Height, c.Rotation, c.Sort, c.DisplayCount}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return nil
}
func (c *CardDeck) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, c.ID, c.Name, c.Type, c.Description, c.Img, c.Folder, c.Width, c.Height, c.Rotation, c.Sort, c.DisplayCount}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return nil
} }
type Card struct { type Card struct {
@@ -38,6 +98,57 @@ type Card struct {
Faces []Face Faces []Face
} }
func (c *Card) Query(data *InsertId[string]) {
data.query = `
INSERT INTO card (card_deck_id, id, name, type, suit, description, origin, width, height, rotation, value, face, sort, drawn)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)`
}
func (c *Card) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[string]{id: c.ID, fieldName: "card_id"}
InsertWithCtxParallel(group, ctx, tx, c.Back, relId)
InsertWithCtxParallel(group, ctx, tx, c.Stats, relId)
InsertSliceParallel(group, tx, c.Faces, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (c *Card) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, c.ID, c.Name, c.Type, c.Suit, c.Description, c.Origin, c.Width, c.Height, c.Rotation, c.Value, c.Sort, c.Drawn}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return nil
}
func (c *Card) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, c.ID, c.Name, c.Type, c.Suit, c.Description, c.Origin, c.Width, c.Height, c.Rotation, c.Value, c.Sort, c.Drawn}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return nil
}
type Face struct { type Face struct {
ID uint ID uint
@@ -46,9 +157,83 @@ type Face struct {
Text string Text string
} }
func (f Face) Query(data *InsertId[string]) {
data.query = `
INSERT INTO face (card_id, name, img, text)
VALUES ($1, $2, $3, $4)
RETURNING id`
}
func (f Face) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, f.Name, f.Img, f.Text}
err := tx.QueryRowx(data.query, args...).Scan(&f.ID)
if err != nil {
return err
}
return nil
}
func (f Face) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, f.Name, f.Img, f.Text}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&f.ID)
if err != nil {
return err
}
return nil
}
type Back struct { type Back struct {
ID uint ID uint
Name string Name string
Text string Text string
} }
func (b Back) Query(data *InsertId[string]) {
data.query = `
INSERT INTO back (card_id, name, text)
VALUES ($1, $2, $3)
RETURNING id`
}
func (b Back) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, b.Name, b.Text}
err := tx.QueryRowx(data.query, args...).Scan(&b.ID)
if err != nil {
return err
}
return nil
}
func (b Back) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, b.Name, b.Text}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&b.ID)
if err != nil {
return err
}
return nil
}

View File

@@ -1,5 +1,14 @@
package db package db
import (
"context"
"database/sql"
"errors"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type Combat struct { type Combat struct {
ID string ID string
@@ -11,9 +20,58 @@ type Combat struct {
Active bool Active bool
Stats Stats Stats Stats
Groups []string Groups []string
Combatants []Combatant Combatants []*Combatant
// System any `json:"system"` }
// Flags any `json:"flags"`
func (c *Combat) Query(data *InsertId[uint]) {
data.query = `
INSERT INTO combat (game_id, id, type, scene, round, turn, sort, active)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`
}
func (c *Combat) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[string]{id: c.ID, fieldName: "combat_id", tableName: "combat_groups"}
InsertWithCtxParallel(group, ctx, tx, c.Stats, relId)
InsertSimpleSliceParallel(group, tx, c.Groups, &relId)
InsertSliceParallel(group, tx, c.Combatants, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (c *Combat) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, c.ID, c.Type, c.Scene, c.Round, c.Turn, c.Sort, c.Active}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return nil
}
func (c *Combat) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, c.ID, c.Type, c.Scene, c.Round, c.Turn, c.Sort, c.Active}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return nil
} }
type Combatant struct { type Combatant struct {
@@ -29,6 +87,53 @@ type Combatant struct {
Hidden bool Hidden bool
Defeated bool Defeated bool
Stats Stats Stats Stats
// System any `json:"system"` }
// Flags any `json:"flags"`
func (c *Combatant) Query(data *InsertId[string]) {
data.query = `
INSERT INTO combatant (combat_id, id, token_id, scene_id, actor_id, img, group_, initiative, hidden, defeated)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`
}
func (c *Combatant) InsertObjects(tx *sqlx.Tx) error {
relId := InsertId[string]{id: c.ID, fieldName: "combat_id"}
group, ctx := errgroup.WithContext(context.Background())
InsertWithCtxParallel(group, ctx, tx, c.Stats, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (c *Combatant) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, c.ID, c.TokenId, c.SceneId, c.ActorId, c.Img, c.Group, c.Initiative, c.Hidden, c.Defeated}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return nil
}
func (c *Combatant) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, c.ID, c.TokenId, c.SceneId, c.ActorId, c.Img, c.Group, c.Initiative, c.Hidden, c.Defeated}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return nil
} }

View File

@@ -29,7 +29,7 @@ func (c Compatibility) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
args := []any{data.id, c.Minimum, c.Verified, c.Maximum} args := []any{data.id, c.Minimum, c.Verified, c.Maximum}
err := tx.QueryRow(data.query, args...).Scan(&c.ID) err := tx.QueryRowx(data.query, args...).Scan(&c.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -44,7 +44,7 @@ func (c Compatibility) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertI
args := []any{data.id, c.Minimum, c.Verified, c.Maximum} args := []any{data.id, c.Minimum, c.Verified, c.Maximum}
err := tx.QueryRowContext(ctx, data.query, args...).Scan(&c.ID) err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&c.ID)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -2,8 +2,12 @@ package db
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
) )
type DocumentTypes struct { type DocumentTypes struct {
@@ -13,10 +17,10 @@ type DocumentTypes struct {
} }
func (d DocumentTypes) Query(data *InsertId[string]) { func (d DocumentTypes) Query(data *InsertId[string]) {
data.query = ` data.query = fmt.Sprintf(`
INSERT INTO document_types (module_id) INSERT INTO document_types (%s)
VALUES ($1) VALUES ($1)
RETURNING id` RETURNING id`, data.fieldName)
} }
func (d DocumentTypes) Insert(tx *sqlx.Tx, data *InsertId[string]) error { func (d DocumentTypes) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
@@ -26,16 +30,19 @@ func (d DocumentTypes) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
args := []any{data.id} args := []any{data.id}
err := tx.QueryRow(data.query, args...).Scan(&d.ID) err := tx.QueryRowx(data.query, args...).Scan(&d.ID)
if err != nil { if err != nil {
return err return err
} }
syncDB := NewSyncDB() group, _ := errgroup.WithContext(context.Background())
defer close(syncDB.errChan) InsertSliceParallel(group, tx, d.Data, InsertId[uint]{id: d.ID})
InsertSliceParallel(syncDB, tx, d.Data, &InsertId[uint]{id: d.ID})
return syncDB.Wait() err = group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
} }
func (d DocumentTypes) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error { func (d DocumentTypes) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
@@ -45,16 +52,19 @@ func (d DocumentTypes) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertI
args := []any{data.id} args := []any{data.id}
err := tx.QueryRowContext(ctx, data.query, args...).Scan(&d.ID) err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&d.ID)
if err != nil { if err != nil {
return err return err
} }
syncDB := NewSyncDB() group, _ := errgroup.WithContext(context.Background())
defer close(syncDB.errChan) InsertSliceParallel(group, tx, d.Data, InsertId[uint]{id: d.ID})
InsertSliceParallel(syncDB, tx, d.Data, &InsertId[uint]{id: d.ID})
return syncDB.Wait() err = group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
} }
type DocumentTypeData struct { type DocumentTypeData struct {
@@ -78,17 +88,16 @@ func (d *DocumentTypeData) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
args := []any{data.id, d.Type} args := []any{data.id, d.Type}
err := tx.QueryRow(data.query, args...).Scan(&d.ID) err := tx.QueryRowx(data.query, args...).Scan(&d.ID)
if err != nil { if err != nil {
return err return err
} }
syncDB := NewSyncDB() group, _ := errgroup.WithContext(context.Background())
defer close(syncDB.errChan)
relData := &InsertId[uint]{id: d.ID, fieldName: "document_types_data_id", tableName: "document_types_data_html"} relData := &InsertId[uint]{id: d.ID, fieldName: "document_types_data_id", tableName: "document_types_data_html"}
InsertSimpleSliceParallel(syncDB, tx, d.HtmlFields, relData) InsertSimpleSliceParallel(group, tx, d.HtmlFields, relData)
return syncDB.Wait() return group.Wait()
} }
func (d *DocumentTypeData) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error { func (d *DocumentTypeData) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
@@ -98,15 +107,14 @@ func (d *DocumentTypeData) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *Ins
args := []any{data.id, d.Type} args := []any{data.id, d.Type}
err := tx.QueryRowContext(ctx, data.query, args...).Scan(&d.ID) err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&d.ID)
if err != nil { if err != nil {
return err return err
} }
syncDB := NewSyncDB() group, _ := errgroup.WithContext(context.Background())
defer close(syncDB.errChan)
relData := &InsertId[uint]{id: d.ID, fieldName: "document_types_data_id", tableName: "document_types_data_html"} relData := &InsertId[uint]{id: d.ID, fieldName: "document_types_data_id", tableName: "document_types_data_html"}
InsertSimpleSliceParallel(syncDB, tx, d.HtmlFields, relData) InsertSimpleSliceParallel(group, tx, d.HtmlFields, relData)
return syncDB.Wait() return group.Wait()
} }

View File

@@ -2,9 +2,12 @@ package db
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt" "fmt"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
) )
type Files struct { type Files struct {
@@ -32,12 +35,15 @@ func (f *Files) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
return err return err
} }
syncDB := NewSyncDB() group, _ := errgroup.WithContext(context.Background())
defer close(syncDB.errChan)
InsertSliceParallel(syncDB, tx, f.Storages, &InsertId[uint]{id: f.ID}) InsertSliceParallel(group, tx, f.Storages, InsertId[uint]{id: f.ID})
return syncDB.Wait() err = group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
} }
func (f *Files) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error { func (f *Files) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
@@ -52,12 +58,15 @@ func (f *Files) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]
return err return err
} }
syncDB := NewSyncDB() group, _ := errgroup.WithContext(context.Background())
defer close(syncDB.errChan)
InsertSliceParallel(syncDB, tx, f.Storages, &InsertId[uint]{id: f.ID}) InsertSliceParallel(group, tx, f.Storages, InsertId[uint]{id: f.ID})
return syncDB.Wait() err = group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
} }
type FilesStorage struct { type FilesStorage struct {

View File

@@ -2,10 +2,13 @@ package db
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt" "fmt"
"strconv" "strconv"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
) )
type Folder struct { type Folder struct {
@@ -26,18 +29,21 @@ func (f *Folder) Query(data *InsertId[string]) {
} }
func (f *Folder) InsertObjects(tx *sqlx.Tx) error { func (f *Folder) InsertObjects(tx *sqlx.Tx) error {
relId := &InsertId[string]{ relId := InsertId[string]{
id: strconv.FormatUint(uint64(f.ID), 10), id: strconv.FormatUint(uint64(f.ID), 10),
fieldName: "folder_id", fieldName: "folder_id",
tableName: "folder_packs", tableName: "folder_packs",
} }
syncDB := NewSyncDB() group, _ := errgroup.WithContext(context.Background())
defer close(syncDB.errChan)
InsertSimpleSliceParallel(syncDB, tx, f.Packs, relId) InsertSimpleSliceParallel(group, tx, f.Packs, &relId)
InsertSliceParallel(syncDB, tx, f.Folders, relId) InsertSliceParallel(group, tx, f.Folders, relId)
return syncDB.Wait() err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
} }
func (f *Folder) Insert(tx *sqlx.Tx, data *InsertId[string]) error { func (f *Folder) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
@@ -47,7 +53,7 @@ func (f *Folder) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
args := []any{data.id, f.Name, f.Sorting, f.Color} args := []any{data.id, f.Name, f.Sorting, f.Color}
err := tx.QueryRow(data.query, args...).Scan(&f.ID) err := tx.QueryRowx(data.query, args...).Scan(&f.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -62,7 +68,7 @@ func (f *Folder) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[stri
args := []any{data.id, f.Name, f.Sorting, f.Color} args := []any{data.id, f.Name, f.Sorting, f.Color}
err := tx.QueryRowContext(ctx, data.query, args...).Scan(&f.ID) err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&f.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -81,5 +87,54 @@ type WorldFolder struct {
Color string Color string
Sort int Sort int
Stats Stats Stats Stats
// Flags any `json:"flags,omitempty"` }
func (w *WorldFolder) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO world_folder (%s, id, name, type, folder, sorting, description, color, sort)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING id`, data.fieldName)
}
func (w *WorldFolder) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[string]{id: w.ID, fieldName: "world_folder_id"}
InsertWithCtxParallel(group, ctx, tx, w.Stats, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (w *WorldFolder) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, w.ID, w.Name, w.Type, w.Folder, w.Sorting, w.Description, w.Color, w.Sort}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return w.InsertObjects(tx)
}
func (w *WorldFolder) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, w.ID, w.Name, w.Type, w.Folder, w.Sorting, w.Description, w.Color, w.Sort}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return w.InsertObjects(tx)
} }

View File

@@ -1,12 +1,25 @@
package db package db
import (
"context"
"database/sql"
"errors"
"strconv"
"time"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type Game struct { type Game struct {
ID uint ID uint
CreatedAt time.Time
DemoMode bool DemoMode bool
IdleLogout bool IdleLogout bool
Paused bool Paused bool
UserID string UserID string
Addresses Addresses Addresses Addresses
Files Files Files Files
Options GameOptions Options GameOptions
@@ -19,17 +32,83 @@ type Game struct {
Modules []*Module Modules []*Module
PackageWarnings []*PackageWarning PackageWarnings []*PackageWarning
Packs []*Pack Packs []*Pack
Messages []Message Messages []*Message
Combats []Combat Combats []*Combat
CardDeck []CardDeck CardDeck []*CardDeck
Users []User Users []*User
Macros []Macro Macros []*Macro
Folders []WorldFolder Folders []*WorldFolder
Items []Item Items []*Item
Settings []Setting Settings []*Setting
Journals []Journal Journals []*Journal
Tables []Table Tables []*Table //
Playlists []Playlist Playlists []*Playlist
Actors []Actor // Actors []Actor //
// Scenes []Scene // Scenes []Scene
} }
func (g *Game) InsertObjects(tx *sqlx.Tx) error {
relData := InsertId[uint]{id: g.ID, fieldName: "game_id"}
group, ctx := errgroup.WithContext(context.Background())
InsertWithCtxParallel(group, ctx, tx, &g.Addresses, relData)
InsertWithCtxParallel(group, ctx, tx, &g.Files, relData)
InsertWithCtxParallel(group, ctx, tx, &g.Options, relData)
InsertWithCtxParallel(group, ctx, tx, &g.Release, relData)
InsertWithCtxParallel(group, ctx, tx, &g.CoreUpdate, relData)
InsertWithCtxParallel(group, ctx, tx, &g.SystemUpdate, relData)
relDataString := InsertId[string]{id: strconv.FormatUint(uint64(g.ID), 10), fieldName: "game_id"}
InsertWithCtxParallel(group, ctx, tx, g.World, relDataString)
InsertWithCtxParallel(group, ctx, tx, g.System, relDataString)
InsertSimpleSliceParallel(group, tx, g.ActiveUsers, &InsertId[uint]{id: g.ID, fieldName: "game_id", tableName: "active_users"})
InsertSliceParallel(group, tx, g.Modules, relData)
InsertSliceParallel(group, tx, g.PackageWarnings, relData)
InsertSliceParallel(group, tx, g.Packs, relDataString)
InsertSliceParallel(group, tx, g.Messages, relData)
InsertSliceParallel(group, tx, g.Combats, relData)
InsertSliceParallel(group, tx, g.CardDeck, relData)
InsertSliceParallel(group, tx, g.Users, relData)
InsertSliceParallel(group, tx, g.Macros, relData)
InsertSliceParallel(group, tx, g.Folders, relData)
InsertSliceParallel(group, tx, g.Items, relData)
InsertSliceParallel(group, tx, g.Settings, relData)
InsertSliceParallel(group, tx, g.Journals, relData)
InsertSliceParallel(group, tx, g.Tables, relData)
InsertSliceParallel(group, tx, g.Playlists, relData)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (g *Game) Insert(db *sqlx.DB) error {
tx := db.MustBegin()
defer tx.Rollback()
const query = `
INSERT INTO game (demo_mode, idle_logout, paused, user_id)
VALUES ($1, $2, $3, $4)
RETURNING id, created_at`
args := []any{g.DemoMode, g.IdleLogout, g.Paused, g.UserID}
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
err := tx.QueryRowxContext(ctx, query, args...).Scan(&g.ID, &g.CreatedAt)
if err != nil {
return err
}
err = g.InsertObjects(tx)
if err != nil {
return err
}
return tx.Commit()
}

View File

@@ -22,7 +22,7 @@ type Grid struct {
func (g *Grid) Query(data *InsertId[string]) { func (g *Grid) Query(data *InsertId[string]) {
data.query = ` data.query = `
INSERT INTO grid (system_id, type, size, distance, diagonals, thickness INSERT INTO grid (system_id, type, size, distance, diagonals, thickness,
alpha, color, units, style) alpha, color, units, style)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING id` RETURNING id`

View File

@@ -15,14 +15,14 @@ type Index struct {
Type string Type string
} }
func (i *Index) Query(data *InsertId[string]) { func (i *Index) Query(data *InsertId[uint]) {
data.query = ` data.query = `
INSERT INTO index_ (pack_id, id, folder, img, name, type) INSERT INTO index_ (pack_id, id, folder, img, name, type)
VALUES ($1, $2, $3, $4, $5, $6) VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id` RETURNING id`
} }
func (i *Index) Insert(tx *sqlx.Tx, data *InsertId[string]) error { func (i *Index) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" { if data.query == "" {
return ErrNoQuery return ErrNoQuery
} }
@@ -37,7 +37,7 @@ func (i *Index) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
return nil return nil
} }
func (i *Index) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error { func (i *Index) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" { if data.query == "" {
return ErrNoQuery return ErrNoQuery
} }

View File

@@ -1,5 +1,15 @@
package db package db
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type Item struct { type Item struct {
ID string ID string
@@ -11,3 +21,54 @@ type Item struct {
Stats Stats Stats Stats
Ownership []OwnershipString Ownership []OwnershipString
} }
func (i *Item) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO world_folder (%s, id, img, name, type, folder, sort)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id`, data.fieldName)
}
func (i *Item) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[string]{id: i.ID, fieldName: "item_id"}
InsertWithCtxParallel(group, ctx, tx, i.Stats, relId)
InsertSliceParallel(group, tx, i.Ownership, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (i *Item) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, i.ID, i.Img, i.Name, i.Type, i.Folder, i.Sort}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return i.InsertObjects(tx)
}
func (i *Item) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, i.ID, i.Img, i.Name, i.Type, i.Folder, i.Sort}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return i.InsertObjects(tx)
}

View File

@@ -1,10 +1,70 @@
package db package db
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type Journal struct { type Journal struct {
ID string ID string
Name string Name string
Sort int Sort int
Pages []JournalPage Pages []*JournalPage
Ownership []OwnershipString Ownership []OwnershipString
} }
func (j *Journal) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO journal (%s, id, name, sort)
VALUES ($1, $2, $3, $4)`, data.fieldName)
}
func (j *Journal) InsertObjects(tx *sqlx.Tx) error {
group, _ := errgroup.WithContext(context.Background())
relId := InsertId[string]{id: j.ID, fieldName: "journal_id"}
InsertSliceParallel(group, tx, j.Pages, relId)
InsertSliceParallel(group, tx, j.Ownership, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (j *Journal) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, j.ID, j.Name, j.Sort}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return j.InsertObjects(tx)
}
func (j *Journal) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, j.ID, j.Name, j.Sort}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return j.InsertObjects(tx)
}

View File

@@ -1,5 +1,15 @@
package db package db
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type JournalPage struct { type JournalPage struct {
ID string ID string
@@ -14,6 +24,60 @@ type JournalPage struct {
Ownership []OwnershipString Ownership []OwnershipString
} }
func (j *JournalPage) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO journal_page (%s, id, name, type, src, sort)
VALUES ($1, $2, $3, $4, $5, $6)`, data.fieldName)
}
func (j *JournalPage) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[string]{id: j.ID, fieldName: "journal_page_id"}
InsertWithCtxParallel(group, ctx, tx, j.Text, relId)
InsertWithCtxParallel(group, ctx, tx, j.Title, relId)
InsertWithCtxParallel(group, ctx, tx, j.Video, relId)
InsertWithCtxParallel(group, ctx, tx, j.Stats, relId)
InsertSliceParallel(group, tx, j.Ownership, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (j *JournalPage) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, j.ID, j.Name, j.Type, j.Src, j.Sort}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return j.InsertObjects(tx)
}
func (j *JournalPage) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, j.ID, j.Name, j.Type, j.Src, j.Sort}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return j.InsertObjects(tx)
}
type PageText struct { type PageText struct {
ID uint ID uint
@@ -22,6 +86,42 @@ type PageText struct {
Format int Format int
} }
func (p PageText) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO journal_page_text (%s, content, markdown, format)
VALUES ($1, $2, $3, $4)`, data.fieldName)
}
func (p PageText) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, p.Content, p.Markdown, p.Format}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return nil
}
func (p PageText) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, p.Content, p.Markdown, p.Format}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return nil
}
type PageTitle struct { type PageTitle struct {
ID uint ID uint
@@ -29,9 +129,81 @@ type PageTitle struct {
Level int Level int
} }
func (p PageTitle) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO journal_page_title (%s, show, level)
VALUES ($1, $2, $3)`, data.fieldName)
}
func (p PageTitle) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, p.Show, p.Level}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return nil
}
func (p PageTitle) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, p.Show, p.Level}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return nil
}
type PageVideo struct { type PageVideo struct {
ID uint ID uint
Controls bool Controls bool
Volume float64 Volume float64
} }
func (p PageVideo) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO journal_page_video (%s, controls, volume)
VALUES ($1, $2, $3)`, data.fieldName)
}
func (p PageVideo) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, p.Controls, p.Volume}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return nil
}
func (p PageVideo) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, p.Controls, p.Volume}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return nil
}

View File

@@ -2,9 +2,12 @@ package db
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt" "fmt"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
) )
type SetupLanguage struct { type SetupLanguage struct {
@@ -33,11 +36,10 @@ func (l *SetupLanguage) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
return err return err
} }
syncDB := NewSyncDB() group, _ := errgroup.WithContext(context.Background())
defer close(syncDB.errChan) InsertSliceParallel(group, tx, l.Modules, InsertId[string]{id: l.ID})
InsertSliceParallel(syncDB, tx, l.Modules, &InsertId[string]{id: l.ID})
return nil return group.Wait()
} }
func (l *SetupLanguage) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error { func (l *SetupLanguage) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
@@ -52,10 +54,13 @@ func (l *SetupLanguage) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *Insert
return err return err
} }
syncDB := NewSyncDB() group, _ := errgroup.WithContext(context.Background())
defer close(syncDB.errChan) InsertSliceParallel(group, tx, l.Modules, InsertId[string]{id: l.ID})
InsertSliceParallel(syncDB, tx, l.Modules, &InsertId[string]{id: l.ID})
err = group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil return nil
} }
@@ -125,7 +130,7 @@ func (l *Language) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
args := []any{data.id, l.Lang, l.Name, l.Path} args := []any{data.id, l.Lang, l.Name, l.Path}
err := tx.QueryRow(data.query, args...).Scan(&l.ID) err := tx.QueryRowx(data.query, args...).Scan(&l.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -140,7 +145,7 @@ func (l *Language) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[st
args := []any{data.id, l.Lang, l.Name, l.Path} args := []any{data.id, l.Lang, l.Name, l.Path}
err := tx.QueryRowContext(ctx, data.query, args...).Scan(&l.ID) err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&l.ID)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -1,5 +1,14 @@
package db package db
import (
"context"
"database/sql"
"errors"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type Macro struct { type Macro struct {
ID string ID string
@@ -14,3 +23,53 @@ type Macro struct {
Stats Stats Stats Stats
Ownership []OwnershipString Ownership []OwnershipString
} }
func (m *Macro) Query(data *InsertId[uint]) {
data.query = `
INSERT INTO macro (game_id, id, command, name, type, img, author, scope, folder, sort)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`
}
func (m *Macro) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[string]{id: m.ID, fieldName: "macro_id"}
InsertWithCtxParallel(group, ctx, tx, m.Stats, relId)
InsertSliceParallel(group, tx, m.Ownership, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (m *Macro) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, m.ID, m.Command, m.Name, m.Type, m.Img, m.Author, m.Scope, m.Folder, m.Sort}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return nil
}
func (m *Macro) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, m.ID, m.Command, m.Name, m.Type, m.Img, m.Author, m.Scope, m.Folder, m.Sort}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return nil
}

View File

@@ -29,7 +29,7 @@ func (m *Media) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
args := []any{data.id, m.Type, m.URL, m.Caption} args := []any{data.id, m.Type, m.URL, m.Caption}
err := tx.QueryRow(data.query, args...).Scan(&m.ID) err := tx.QueryRowx(data.query, args...).Scan(&m.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -44,7 +44,7 @@ func (m *Media) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[strin
args := []any{data.id, m.Type, m.URL, m.Caption} args := []any{data.id, m.Type, m.URL, m.Caption}
err := tx.QueryRowContext(ctx, data.query, args...).Scan(&m.ID) err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&m.ID)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -1,5 +1,15 @@
package db package db
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type Message struct { type Message struct {
ID string ID string
@@ -18,6 +28,59 @@ type Message struct {
Rolls []string Rolls []string
} }
func (m *Message) Query(data *InsertId[uint]) {
data.query = `
INSERT INTO addresses (game_id, id, blind, emote, style, timestamp, content, author, type, flavor, sound)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`
}
func (m *Message) InsertObjects(tx *sqlx.Tx) error {
relId := InsertId[string]{id: m.ID, fieldName: "message_id"}
group, ctx := errgroup.WithContext(context.Background())
InsertWithCtxParallel(group, ctx, tx, m.Stats, relId)
InsertWithCtxParallel(group, ctx, tx, m.Speaker, relId)
InsertSimpleSliceParallel(group, tx, m.Whisper, &InsertId[string]{id: m.ID, fieldName: "message_id", tableName: "message_whisper"})
InsertSimpleSliceParallel(group, tx, m.Rolls, &InsertId[string]{id: m.ID, fieldName: "message_id", tableName: "message_rolls"})
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (m *Message) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, m.ID, m.Blind, m.Emote, m.Style, m.Timestamp, m.Content, m.Author, m.Type, m.Flavor, m.Sound}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return nil
}
func (m *Message) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, m.ID, m.Blind, m.Emote, m.Style, m.Timestamp, m.Content, m.Author, m.Type, m.Flavor, m.Sound}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return nil
}
type Speaker struct { type Speaker struct {
ID uint ID uint
@@ -26,3 +89,39 @@ type Speaker struct {
Token string Token string
Alias string Alias string
} }
func (s Speaker) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO speaker (%s, scene, actor, token, alias)
VALUES ($1, $2, $3, $4, $5, $6)`, data.fieldName)
}
func (s Speaker) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.Scene, s.Actor, s.Token, s.Alias}
err := tx.QueryRowx(data.query, args...).Scan(&s.ID)
if err != nil {
return err
}
return nil
}
func (s Speaker) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.Scene, s.Actor, s.Token, s.Alias}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&s.ID)
if err != nil {
return err
}
return nil
}

View File

@@ -2,9 +2,12 @@ package db
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt" "fmt"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
) )
type Module struct { type Module struct {
@@ -55,29 +58,32 @@ func (m *Module) Query(data *InsertId[uint]) {
} }
func (m *Module) InsertObjects(tx *sqlx.Tx) error { func (m *Module) InsertObjects(tx *sqlx.Tx) error {
relId := &InsertId[string]{id: m.ID, fieldName: "module_id"} relId := InsertId[string]{id: m.ID, fieldName: "module_id"}
syncDB := NewSyncDB() group, ctx := errgroup.WithContext(context.Background())
defer close(syncDB.errChan)
go InsertWithCtxParallel(syncDB, tx, m.DocumentTypes, relId) InsertWithCtxParallel(group, ctx, tx, m.DocumentTypes, relId)
go InsertWithCtxParallel(syncDB, tx, m.Relationships, relId) InsertWithCtxParallel(group, ctx, tx, m.Relationships, relId)
go InsertWithCtxParallel(syncDB, tx, m.Compatibility, relId) InsertWithCtxParallel(group, ctx, tx, m.Compatibility, relId)
scriptRelId := &InsertId[string]{id: m.ID, fieldName: "module_id", tableName: "scripts"} // scriptRelId := &InsertId[string]{id: m.ID, fieldName: "module_id", tableName: "scripts"}
go InsertSimpleSliceParallel(syncDB, tx, m.Scripts, scriptRelId) // InsertSimpleSliceParallel(group, tx, m.Scripts, scriptRelId)
esModulesRelId := &InsertId[string]{id: m.ID, fieldName: "module_id", tableName: "es_modules"} // esModulesRelId := &InsertId[string]{id: m.ID, fieldName: "module_id", tableName: "es_modules"}
go InsertSimpleSliceParallel(syncDB, tx, m.Esmodules, esModulesRelId) // InsertSimpleSliceParallel(group, tx, m.Esmodules, esModulesRelId)
tagsRelId := &InsertId[string]{id: m.ID, fieldName: "module_id", tableName: "tags"} // tagsRelId := &InsertId[string]{id: m.ID, fieldName: "module_id", tableName: "tags"}
go InsertSimpleSliceParallel(syncDB, tx, m.Tags, tagsRelId) // InsertSimpleSliceParallel(group, tx, m.Tags, tagsRelId)
go InsertSliceParallel(syncDB, tx, m.Authors, relId) // InsertSliceParallel(group, tx, m.Authors, relId)
go InsertSliceParallel(syncDB, tx, m.Media, relId) // InsertSliceParallel(group, tx, m.Media, relId)
go InsertSliceParallel(syncDB, tx, m.Styles, relId) // InsertSliceParallel(group, tx, m.Styles, relId)
go InsertSliceParallel(syncDB, tx, m.Languages, relId) // InsertSliceParallel(group, tx, m.Languages, relId)
go InsertSliceParallel(syncDB, tx, m.Packs, relId) // InsertSliceParallel(group, tx, m.Packs, relId)
go InsertSliceParallel(syncDB, tx, m.PackFolders, relId) // InsertSliceParallel(group, tx, m.PackFolders, relId)
return syncDB.Wait() err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
} }
func (m *Module) Insert(tx *sqlx.Tx, data *InsertId[uint]) error { func (m *Module) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {

View File

@@ -14,15 +14,21 @@ type GameOptions struct {
Port int Port int
} }
func (g *GameOptions) Insert(tx *sqlx.Tx, gameId *InsertId[uint]) error { func (g *GameOptions) Query(data *InsertId[uint]) {
query := ` data.query = `
INSERT INTO featured_content (game_id, language, update_channel, port) INSERT INTO featured_content (game_id, language, update_channel, port)
VALUES ($1, $2, $3, $4) VALUES ($1, $2, $3, $4)
RETURNING id` RETURNING id`
}
args := []any{gameId.id, g.Language, g.UpdateChannel, g.Port} func (g *GameOptions) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
err := tx.QueryRowx(query, args...).Scan(&g.ID) args := []any{data.id, g.Language, g.UpdateChannel, g.Port}
err := tx.QueryRowx(data.query, args...).Scan(&g.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -30,15 +36,14 @@ func (g *GameOptions) Insert(tx *sqlx.Tx, gameId *InsertId[uint]) error {
return nil return nil
} }
func (g *GameOptions) InsertCtx(ctx context.Context, tx *sqlx.Tx, gameId *InsertId[uint]) error { func (g *GameOptions) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
query := ` if data.query == "" {
INSERT INTO featured_content (game_id, language, update_channel, port) return ErrNoQuery
VALUES ($1, $2, $3, $4) }
RETURNING id`
args := []any{gameId.id, g.Language, g.UpdateChannel, g.Port} args := []any{data.id, g.Language, g.UpdateChannel, g.Port}
err := tx.QueryRowxContext(ctx, query, args...).Scan(&g.ID) err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&g.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -71,7 +76,7 @@ func (s *SetupOptions) Query(data *InsertId[uint]) {
data.query = ` data.query = `
INSERT INTO setup_options (setup_id, css_theme, data_path, hostname, language, local_hostname, INSERT INTO setup_options (setup_id, css_theme, data_path, hostname, language, local_hostname,
update_channel, port, compress_socket, compress_static, fullscreen, hot_reload, proxy_ssl, update_channel, port, compress_socket, compress_static, fullscreen, hot_reload, proxy_ssl,
telemetry, upnp, delete_nedb, no_backups,) telemetry, upnp, delete_nedb, no_backups)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
RETURNING id` RETURNING id`
} }

View File

@@ -2,6 +2,7 @@ package db
import ( import (
"context" "context"
"fmt"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
) )
@@ -15,10 +16,10 @@ type Ownership struct {
} }
func (o Ownership) Query(data *InsertId[string]) { func (o Ownership) Query(data *InsertId[string]) {
data.query = ` data.query = fmt.Sprintf(`
INSERT INTO ownership (%s, player, trusted, assistant) INSERT INTO ownership (%s, player, trusted, assistant)
VALUES ($1, $2, $3, $4) VALUES ($1, $2, $3, $4)
RETURNING id` RETURNING id`, data.fieldName)
} }
func (o Ownership) Insert(tx *sqlx.Tx, data *InsertId[string]) error { func (o Ownership) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
@@ -28,7 +29,7 @@ func (o Ownership) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
args := []any{data.id, o.Player, o.Trusted, o.Assistant} args := []any{data.id, o.Player, o.Trusted, o.Assistant}
err := tx.QueryRow(data.query, args...).Scan(&o.ID) err := tx.QueryRowx(data.query, args...).Scan(&o.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -43,7 +44,7 @@ func (o Ownership) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[st
args := []any{data.id, o.Player, o.Trusted, o.Assistant} args := []any{data.id, o.Player, o.Trusted, o.Assistant}
err := tx.QueryRowContext(ctx, data.query, args...).Scan(&o.ID) err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&o.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -57,3 +58,40 @@ type OwnershipString struct {
Key string Key string
Value int Value int
} }
func (o OwnershipString) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO ownership_string (%s, key_, value)
VALUES ($1, $2, $3)
RETURNING id`, data.fieldName)
}
func (o OwnershipString) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, o.Key, o.Value}
err := tx.QueryRowx(data.query, args...).Scan(&o.ID)
if err != nil {
return err
}
return nil
}
func (o OwnershipString) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, o.Key, o.Value}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&o.ID)
if err != nil {
return err
}
return nil
}

View File

@@ -2,14 +2,19 @@ package db
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt" "fmt"
"strconv"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
) )
type Pack struct { type Pack struct {
ID string ID uint
Key string
Name string Name string
Label string Label string
Banner string Banner string
@@ -25,21 +30,26 @@ type Pack struct {
func (p *Pack) Query(data *InsertId[string]) { func (p *Pack) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(` data.query = fmt.Sprintf(`
INSERT INTO pack (%s, id, name, label, banner, path, type, system, package_type, package_name) INSERT INTO pack (%s, key_, name, label, banner, path, type, system, package_type, package_name)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING id`, data.fieldName) RETURNING id`, data.fieldName)
} }
func (p *Pack) InsertObjects(tx *sqlx.Tx) error { func (p *Pack) InsertObjects(tx *sqlx.Tx) error {
relId := &InsertId[string]{id: p.ID, fieldName: "pack_id"} group, ctx := errgroup.WithContext(context.Background())
syncDB := NewSyncDB()
defer close(syncDB.errChan)
InsertWithCtxParallel(syncDB, tx, p.Ownership, relId) InsertWithCtxParallel(group, ctx, tx, p.Ownership,
InsertSliceParallel(syncDB, tx, p.Index, relId) InsertId[string]{id: strconv.FormatUint(uint64(p.ID), 10), fieldName: "pack_id"})
InsertSliceParallel(syncDB, tx, p.Folders, relId)
return syncDB.Wait() relId := InsertId[uint]{id: p.ID, fieldName: "pack_id"}
InsertSliceParallel(group, tx, p.Index, relId)
InsertSliceParallel(group, tx, p.Folders, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
} }
func (p *Pack) Insert(tx *sqlx.Tx, data *InsertId[string]) error { func (p *Pack) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
@@ -47,9 +57,9 @@ func (p *Pack) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
return ErrNoQuery return ErrNoQuery
} }
args := []any{data.id, p.ID, p.Name, p.Label, p.Banner, p.Path, p.Type, p.System, p.PackageType, p.PackageName} args := []any{data.id, p.Key, p.Name, p.Label, p.Banner, p.Path, p.Type, p.System, p.PackageType, p.PackageName}
_, err := tx.Exec(data.query, args...) err := tx.QueryRowx(data.query, args...).Scan(&p.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -62,9 +72,9 @@ func (p *Pack) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string
return ErrNoQuery return ErrNoQuery
} }
args := []any{data.id, p.ID, p.Name, p.Label, p.Banner, p.Path, p.Type, p.System, p.PackageType, p.PackageName} args := []any{data.id, p.Key, p.Name, p.Label, p.Banner, p.Path, p.Type, p.System, p.PackageType, p.PackageName}
_, err := tx.ExecContext(ctx, data.query, args...) err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&p.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -82,13 +92,13 @@ type PackFolder struct {
Sort int Sort int
} }
func (p *PackFolder) Query(data *InsertId[string]) { func (p *PackFolder) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(` data.query = fmt.Sprintf(`
INSERT INTO pack_folder (%s, id, description, name, sorting, type, sort) INSERT INTO pack_folder (%s, id, description, name, sorting, type, sort)
VALUES ($1, $2, $3, $4, $5, $6, $7)`, data.fieldName) VALUES ($1, $2, $3, $4, $5, $6, $7)`, data.fieldName)
} }
func (p *PackFolder) Insert(tx *sqlx.Tx, data *InsertId[string]) error { func (p *PackFolder) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" { if data.query == "" {
return ErrNoQuery return ErrNoQuery
} }
@@ -103,7 +113,7 @@ func (p *PackFolder) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
return nil return nil
} }
func (p *PackFolder) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error { func (p *PackFolder) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" { if data.query == "" {
return ErrNoQuery return ErrNoQuery
} }

View File

@@ -2,13 +2,16 @@ package db
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt" "fmt"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
) )
type PackageWarning struct { type PackageWarning struct {
ID string ID uint
Key string Key string
Value *PackageWarningsData Value *PackageWarningsData
@@ -16,8 +19,9 @@ type PackageWarning struct {
func (p *PackageWarning) Query(data *InsertId[uint]) { func (p *PackageWarning) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(` data.query = fmt.Sprintf(`
INSERT INTO package_warnings (%s, id) INSERT INTO package_warnings (%s, key_)
VALUES ($1, $2)`, data.fieldName) VALUES ($1, $2)
RETURNING id`, data.fieldName)
} }
func (p *PackageWarning) Insert(tx *sqlx.Tx, data *InsertId[uint]) error { func (p *PackageWarning) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
@@ -25,14 +29,14 @@ func (p *PackageWarning) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
return ErrNoQuery return ErrNoQuery
} }
args := []any{data.id, p.ID} args := []any{data.id, p.Key}
_, err := tx.Exec(data.query, args...) err := tx.QueryRowx(data.query, args...).Scan(&p.ID)
if err != nil { if err != nil {
return err return err
} }
InsertWithCtx(tx, p.Value, &InsertId[string]{id: p.ID}) InsertWithCtx(tx, p.Value, InsertId[uint]{id: p.ID})
return nil return nil
} }
@@ -42,16 +46,14 @@ func (p *PackageWarning) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *Inser
return ErrNoQuery return ErrNoQuery
} }
args := []any{data.id, p.ID} args := []any{data.id, p.Key}
_, err := tx.Exec(data.query, args...) err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&p.ID)
if err != nil { if err != nil {
return err return err
} }
InsertWithCtx(tx, p.Value, &InsertId[string]{id: p.ID}) return InsertWithCtx(tx, p.Value, InsertId[uint]{id: p.ID})
return nil
} }
type PackageWarningsData struct { type PackageWarningsData struct {
@@ -65,23 +67,27 @@ type PackageWarningsData struct {
} }
func (p *PackageWarningsData) InsertObjects(tx *sqlx.Tx) error { func (p *PackageWarningsData) InsertObjects(tx *sqlx.Tx) error {
syncDB := NewSyncDB() group, _ := errgroup.WithContext(context.Background())
defer close(syncDB.errChan)
warningData := &InsertId[string]{id: p.ID, fieldName: "package_warnings_data_id", tableName: "package_warnings_data_warning"} warningData := &InsertId[string]{id: p.ID, fieldName: "package_warnings_data_id", tableName: "package_warnings_data_warning"}
InsertSimpleSliceParallel(syncDB, tx, p.Warning, warningData) InsertSimpleSliceParallel(group, tx, p.Warning, warningData)
errorData := &InsertId[string]{id: p.ID, fieldName: "package_warnings_data_id", tableName: "package_warnings_data_error"} errorData := &InsertId[string]{id: p.ID, fieldName: "package_warnings_data_id", tableName: "package_warnings_data_error"}
InsertSimpleSliceParallel(syncDB, tx, p.Warning, errorData) InsertSimpleSliceParallel(group, tx, p.Warning, errorData)
return syncDB.Wait() err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
} }
func (p *PackageWarningsData) Query(data *InsertId[string]) { func (p *PackageWarningsData) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(` data.query = `
INSERT INTO package_warnings_data (%s, id, type, reinstallable, manifest) INSERT INTO package_warnings_data (package_warnings_id, id, type, reinstallable, manifest)
VALUES ($1, $2, $3, $4, $5)`, data.fieldName) VALUES ($1, $2, $3, $4, $5)`
} }
func (p *PackageWarningsData) Insert(tx *sqlx.Tx, data *InsertId[string]) error { func (p *PackageWarningsData) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" { if data.query == "" {
return ErrNoQuery return ErrNoQuery
} }
@@ -96,7 +102,7 @@ func (p *PackageWarningsData) Insert(tx *sqlx.Tx, data *InsertId[string]) error
return p.InsertObjects(tx) return p.InsertObjects(tx)
} }
func (p *PackageWarningsData) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error { func (p *PackageWarningsData) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" { if data.query == "" {
return ErrNoQuery return ErrNoQuery
} }

View File

@@ -1,5 +1,15 @@
package db package db
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type Playlist struct { type Playlist struct {
ID string ID string
@@ -15,7 +25,58 @@ type Playlist struct {
Playing bool Playing bool
Stats Stats Stats Stats
Ownership []OwnershipString Ownership []OwnershipString
Sounds []Sound Sounds []*Sound
}
func (p *Playlist) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO playlist (%s, id, name, folder, sorting, description, channel, mode, fade, seed, sort, playing)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`, data.fieldName)
}
func (p *Playlist) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[string]{id: p.ID, fieldName: "playlist_id"}
InsertWithCtxParallel(group, ctx, tx, p.Stats, relId)
InsertSliceParallel(group, tx, p.Ownership, relId)
InsertSliceParallel(group, tx, p.Sounds, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (p *Playlist) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, p.ID, p.Name, p.Folder, p.Sorting, p.Description, p.Channel, p.Mode, p.Fade, p.Seed, p.Sort, p.Playing}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return p.InsertObjects(tx)
}
func (p *Playlist) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, p.ID, p.Name, p.Folder, p.Sorting, p.Description, p.Channel, p.Mode, p.Fade, p.Seed, p.Sort, p.Playing}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return p.InsertObjects(tx)
} }
type Sound struct { type Sound struct {
@@ -32,3 +93,39 @@ type Sound struct {
Volume float64 Volume float64
PausedTime float64 PausedTime float64
} }
func (s *Sound) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO Sound (%s, id, name, path, channel, description, fade, sort, repeat, playing, volume, paused_time)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`, data.fieldName)
}
func (s *Sound) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.ID, s.Name, s.Path, s.Channel, s.Description, s.Fade, s.Sort, s.Repeat, s.Playing, s.Volume, s.PausedTime}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return nil
}
func (s *Sound) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.ID, s.Name, s.Path, s.Channel, s.Description, s.Fade, s.Sort, s.Repeat, s.Playing, s.Volume, s.PausedTime}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return nil
}

View File

@@ -2,9 +2,13 @@ package db
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt" "fmt"
"strconv"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
) )
type Relationships struct { type Relationships struct {
@@ -35,15 +39,18 @@ func (r Relationships) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
return err return err
} }
syncDB := NewSyncDB() group, _ := errgroup.WithContext(context.Background())
defer close(syncDB.errChan)
InsertSliceParallel(syncDB, tx, r.Systems, &InsertId[uint]{id: r.ID, tableName: "relationships_systems"}) InsertSliceParallel(group, tx, r.Systems, InsertId[uint]{id: r.ID, tableName: "relationships_systems"})
InsertSliceParallel(syncDB, tx, r.Requires, &InsertId[uint]{id: r.ID, tableName: "relationships_requires"}) InsertSliceParallel(group, tx, r.Requires, InsertId[uint]{id: r.ID, tableName: "relationships_requires"})
InsertSliceParallel(syncDB, tx, r.Recommends, &InsertId[uint]{id: r.ID, tableName: "relationships_recommends"}) InsertSliceParallel(group, tx, r.Recommends, InsertId[uint]{id: r.ID, tableName: "relationships_recommends"})
InsertSliceParallel(syncDB, tx, r.Conflicts, &InsertId[uint]{id: r.ID, tableName: "relationships_conflicts"}) InsertSliceParallel(group, tx, r.Conflicts, InsertId[uint]{id: r.ID, tableName: "relationships_conflicts"})
return syncDB.Wait() err = group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
} }
func (r Relationships) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error { func (r Relationships) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
@@ -58,20 +65,24 @@ func (r Relationships) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertI
return err return err
} }
syncDB := NewSyncDB() group, _ := errgroup.WithContext(context.Background())
defer close(syncDB.errChan)
InsertSliceParallel(syncDB, tx, r.Systems, &InsertId[uint]{id: r.ID, tableName: "relationships_systems"}) InsertSliceParallel(group, tx, r.Systems, InsertId[uint]{id: r.ID, tableName: "relationships_systems"})
InsertSliceParallel(syncDB, tx, r.Requires, &InsertId[uint]{id: r.ID, tableName: "relationships_requires"}) InsertSliceParallel(group, tx, r.Requires, InsertId[uint]{id: r.ID, tableName: "relationships_requires"})
InsertSliceParallel(syncDB, tx, r.Recommends, &InsertId[uint]{id: r.ID, tableName: "relationships_recommends"}) InsertSliceParallel(group, tx, r.Recommends, InsertId[uint]{id: r.ID, tableName: "relationships_recommends"})
InsertSliceParallel(syncDB, tx, r.Conflicts, &InsertId[uint]{id: r.ID, tableName: "relationships_conflicts"}) InsertSliceParallel(group, tx, r.Conflicts, InsertId[uint]{id: r.ID, tableName: "relationships_conflicts"})
return syncDB.Wait() err = group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
} }
type RelationshipsData struct { type RelationshipsData struct {
ID string ID uint
Key string
Type string Type string
Manifest string Manifest string
Compatibility Compatibility Compatibility Compatibility
@@ -79,8 +90,8 @@ type RelationshipsData struct {
func (r RelationshipsData) Query(data *InsertId[uint]) { func (r RelationshipsData) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(` data.query = fmt.Sprintf(`
INSERT INTO %s (relationships_id, id, type, manifest) INSERT INTO %s (relationships_id, key_, type, manifest)
VALUES ($1, $2, $3, $4, $5)`, data.tableName) VALUES ($1, $2, $3, $4)`, data.tableName)
} }
func (r RelationshipsData) Insert(tx *sqlx.Tx, data *InsertId[uint]) error { func (r RelationshipsData) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
@@ -88,18 +99,17 @@ func (r RelationshipsData) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
return ErrNoQuery return ErrNoQuery
} }
args := []any{data.id, r.ID, r.Type, r.Manifest} args := []any{data.id, r.Key, r.Type, r.Manifest}
_, err := tx.Exec(data.query, args...) err := tx.QueryRowx(data.query, args...).Scan(&r.ID)
if err != nil { if err != nil {
return err return err
} }
syncDB := NewSyncDB() group, ctx := errgroup.WithContext(context.Background())
defer close(syncDB.errChan) InsertWithCtxParallel(group, ctx, tx, r.Compatibility, InsertId[string]{id: strconv.FormatUint(uint64(r.ID), 10), fieldName: fmt.Sprintf("%s_id", data.tableName)})
InsertWithCtxParallel(syncDB, tx, r.Compatibility, &InsertId[string]{id: r.ID, fieldName: fmt.Sprintf("%s_id", data.tableName)})
return nil return group.Wait()
} }
func (r RelationshipsData) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error { func (r RelationshipsData) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
@@ -107,16 +117,15 @@ func (r RelationshipsData) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *Ins
return ErrNoQuery return ErrNoQuery
} }
args := []any{data.id, r.ID, r.Type, r.Manifest} args := []any{data.id, r.Key, r.Type, r.Manifest}
_, err := tx.ExecContext(ctx, data.query, args...) err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&r.ID)
if err != nil { if err != nil {
return err return err
} }
syncDB := NewSyncDB() group, ctx := errgroup.WithContext(context.Background())
defer close(syncDB.errChan) InsertWithCtxParallel(group, ctx, tx, r.Compatibility, InsertId[string]{id: strconv.FormatUint(uint64(r.ID), 10), fieldName: fmt.Sprintf("%s_id", data.tableName)})
InsertWithCtxParallel(syncDB, tx, r.Compatibility, &InsertId[string]{id: r.ID, fieldName: fmt.Sprintf("%s_id", data.tableName)})
return nil return group.Wait()
} }

View File

@@ -22,7 +22,7 @@ type Release struct {
func (r *Release) Query(data *InsertId[uint]) { func (r *Release) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(` data.query = fmt.Sprintf(`
INSERT INTO release_ (%s, generaion, build, node_version, max_generation, max_stable_generation, INSERT INTO release_ (%s, generation, build, node_version, max_generation, max_stable_generation,
time, channel, suffix) time, channel, suffix)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING id`, data.fieldName) RETURNING id`, data.fieldName)

View File

@@ -1,5 +1,15 @@
package db package db
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type Setting struct { type Setting struct {
ID string ID string
@@ -7,3 +17,52 @@ type Setting struct {
Value string Value string
Stats Stats Stats Stats
} }
func (s *Setting) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO setting (%s, id, key_, value)
VALUES ($1, $2, $3, $4)`, data.fieldName)
}
func (s *Setting) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[string]{id: s.ID, fieldName: "setting_id"}
InsertWithCtxParallel(group, ctx, tx, s.Stats, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (s *Setting) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.ID, s.Key, s.Value}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return s.InsertObjects(tx)
}
func (s *Setting) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.ID, s.Key, s.Value}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return s.InsertObjects(tx)
}

View File

@@ -2,10 +2,13 @@ package db
import ( import (
"context" "context"
"database/sql"
"errors"
"strconv" "strconv"
"time" "time"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
) )
type Setup struct { type Setup struct {
@@ -28,29 +31,32 @@ type Setup struct {
} }
func (s *Setup) InsertObjects(tx *sqlx.Tx) error { func (s *Setup) InsertObjects(tx *sqlx.Tx) error {
relData := &InsertId[uint]{id: s.ID, fieldName: "setup_id"} relData := InsertId[uint]{id: s.ID, fieldName: "setup_id"}
syncDB := NewSyncDB() group, ctx := errgroup.WithContext(context.Background())
defer close(syncDB.errChan)
InsertWithCtxParallel(syncDB, tx, &s.CoreUpdate, relData) InsertWithCtxParallel(group, ctx, tx, &s.CoreUpdate, relData)
InsertWithCtxParallel(syncDB, tx, &s.FeaturedContent, relData) InsertWithCtxParallel(group, ctx, tx, &s.FeaturedContent, relData)
InsertWithCtxParallel(syncDB, tx, &s.Files, relData) InsertWithCtxParallel(group, ctx, tx, &s.Files, relData)
InsertWithCtxParallel(syncDB, tx, s.Options, relData) InsertWithCtxParallel(group, ctx, tx, s.Options, relData)
InsertWithCtxParallel(syncDB, tx, &s.Release, relData) InsertWithCtxParallel(group, ctx, tx, &s.Release, relData)
InsertSliceParallel(syncDB, tx, s.Languages, relData) InsertSliceParallel(group, tx, s.Languages, relData)
InsertSliceParallel(syncDB, tx, s.Modules, relData) InsertSliceParallel(group, tx, s.Modules, relData)
InsertSliceParallel(syncDB, tx, s.News, relData) InsertSliceParallel(group, tx, s.News, relData)
InsertSliceParallel(syncDB, tx, s.PackageWarnings, relData) InsertSliceParallel(group, tx, s.PackageWarnings, relData)
relDataString := &InsertId[string]{ relDataString := InsertId[string]{
id: strconv.FormatUint(uint64(s.ID), 10), id: strconv.FormatUint(uint64(s.ID), 10),
fieldName: "setup_id", fieldName: "setup_id",
} }
InsertSliceParallel(syncDB, tx, s.Systems, relDataString) InsertSliceParallel(group, tx, s.Systems, relDataString)
InsertSliceParallel(syncDB, tx, s.Worlds, relDataString) InsertSliceParallel(group, tx, s.Worlds, relDataString)
return syncDB.Wait() err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
} }
func (s *Setup) Insert(db *sqlx.DB) error { func (s *Setup) Insert(db *sqlx.DB) error {
@@ -67,7 +73,7 @@ func (s *Setup) Insert(db *sqlx.DB) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
err := tx.QueryRowContext(ctx, query, args...).Scan(&s.ID, &s.CreatedAt) err := tx.QueryRowxContext(ctx, query, args...).Scan(&s.ID, &s.CreatedAt)
if err != nil { if err != nil {
return err return err
} }
@@ -149,7 +155,7 @@ func (n *News) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
args := []any{data.id, n.Title, n.Caption, n.URL, n.Image} args := []any{data.id, n.Title, n.Caption, n.URL, n.Image}
err := tx.QueryRow(data.query, args...).Scan(&n.ID) err := tx.QueryRowx(data.query, args...).Scan(&n.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -164,7 +170,7 @@ func (n *News) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint])
args := []any{data.id, n.Title, n.Caption, n.URL, n.Image} args := []any{data.id, n.Title, n.Caption, n.URL, n.Image}
err := tx.QueryRowContext(ctx, data.query, args...).Scan(&n.ID) err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&n.ID)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -1,5 +1,12 @@
package db package db
import (
"context"
"fmt"
"github.com/jmoiron/sqlx"
)
type Stats struct { type Stats struct {
ID uint ID uint
@@ -9,3 +16,39 @@ type Stats struct {
LastModifiedBy string LastModifiedBy string
ModifiedTime int64 ModifiedTime int64
} }
func (s Stats) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO stats (%s, core_version, system_id, system_version, last_modified_by, modified_time)
VALUES ($1, $2, $3, $4, $5, $6)`, data.fieldName)
}
func (s Stats) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.CoreVersion, s.SystemID, s.SystemVersion, s.LastModifiedBy, s.ModifiedTime}
err := tx.QueryRowx(data.query, args...).Scan(&s.ID)
if err != nil {
return err
}
return nil
}
func (s Stats) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.CoreVersion, s.SystemID, s.SystemVersion, s.LastModifiedBy, s.ModifiedTime}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&s.ID)
if err != nil {
return err
}
return nil
}

View File

@@ -27,7 +27,7 @@ func (s *Style) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
args := []any{data.id, s.Src} args := []any{data.id, s.Src}
err := tx.QueryRow(data.query, args...).Scan(&s.ID) err := tx.QueryRowx(data.query, args...).Scan(&s.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -42,7 +42,7 @@ func (s *Style) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[strin
args := []any{data.id, s.Src} args := []any{data.id, s.Src}
err := tx.QueryRowContext(ctx, data.query, args...).Scan(&s.ID) err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&s.ID)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -2,9 +2,12 @@ package db
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt" "fmt"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
) )
type System struct { type System struct {
@@ -54,30 +57,33 @@ func (s *System) Query(data *InsertId[string]) {
} }
func (s *System) InsertObjects(tx *sqlx.Tx) error { func (s *System) InsertObjects(tx *sqlx.Tx) error {
relId := &InsertId[string]{id: s.ID, fieldName: "system_id"} relId := InsertId[string]{id: s.ID, fieldName: "system_id"}
syncDB := NewSyncDB() group, ctx := errgroup.WithContext(context.Background())
defer close(syncDB.errChan)
InsertWithCtxParallel(syncDB, tx, s.Compatibility, relId) InsertWithCtxParallel(group, ctx, tx, s.Compatibility, relId)
InsertWithCtxParallel(syncDB, tx, s.Relationships, relId) InsertWithCtxParallel(group, ctx, tx, s.Relationships, relId)
InsertWithCtxParallel(syncDB, tx, s.DocumentTypes, relId) InsertWithCtxParallel(group, ctx, tx, s.DocumentTypes, relId)
InsertWithCtxParallel(syncDB, tx, s.Grid, relId) InsertWithCtxParallel(group, ctx, tx, s.Grid, relId)
esModulesRelId := &InsertId[string]{id: s.ID, fieldName: "system_id", tableName: "es_modules"} esModulesRelId := &InsertId[string]{id: s.ID, fieldName: "system_id", tableName: "es_modules"}
InsertSimpleSliceParallel(syncDB, tx, s.Esmodules, esModulesRelId) InsertSimpleSliceParallel(group, tx, s.Esmodules, esModulesRelId)
scriptRelId := &InsertId[string]{id: s.ID, fieldName: "system_id", tableName: "scripts"} scriptRelId := &InsertId[string]{id: s.ID, fieldName: "system_id", tableName: "scripts"}
InsertSimpleSliceParallel(syncDB, tx, s.Scripts, scriptRelId) InsertSimpleSliceParallel(group, tx, s.Scripts, scriptRelId)
tagsRelId := &InsertId[string]{id: s.ID, fieldName: "system_id", tableName: "tags"} tagsRelId := &InsertId[string]{id: s.ID, fieldName: "system_id", tableName: "tags"}
InsertSimpleSliceParallel(syncDB, tx, s.Tags, tagsRelId) InsertSimpleSliceParallel(group, tx, s.Tags, tagsRelId)
InsertSliceParallel(syncDB, tx, s.Authors, relId) InsertSliceParallel(group, tx, s.Authors, relId)
InsertSliceParallel(syncDB, tx, s.Media, relId) InsertSliceParallel(group, tx, s.Media, relId)
InsertSliceParallel(syncDB, tx, s.Styles, relId) InsertSliceParallel(group, tx, s.Styles, relId)
InsertSliceParallel(syncDB, tx, s.Languages, relId) InsertSliceParallel(group, tx, s.Languages, relId)
InsertSliceParallel(syncDB, tx, s.Packs, relId) InsertSliceParallel(group, tx, s.Packs, relId)
InsertSliceParallel(syncDB, tx, s.PackFolders, relId) InsertSliceParallel(group, tx, s.PackFolders, relId)
return syncDB.Wait() err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
} }
func (s *System) Insert(tx *sqlx.Tx, data *InsertId[string]) error { func (s *System) Insert(tx *sqlx.Tx, data *InsertId[string]) error {

View File

@@ -1,5 +1,15 @@
package db package db
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type Table struct { type Table struct {
ID string ID string
@@ -13,7 +23,58 @@ type Table struct {
DisplayRoll bool DisplayRoll bool
Stats Stats Stats Stats
Ownership []OwnershipString Ownership []OwnershipString
Results []TableResult Results []*TableResult
}
func (t *Table) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO table_ (%s, id, name, description, formula, img, folder, sort, replacement, display_roll)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`, data.fieldName)
}
func (t *Table) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[string]{id: t.ID, fieldName: "table_id"}
InsertWithCtxParallel(group, ctx, tx, t.Stats, relId)
InsertSliceParallel(group, tx, t.Ownership, relId)
InsertSliceParallel(group, tx, t.Results, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (t *Table) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.ID, t.Name, t.Description, t.Formula, t.Img, t.Folder, t.Sort, t.Replacement, t.DisplayRoll}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return t.InsertObjects(tx)
}
func (t *Table) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.ID, t.Name, t.Description, t.Formula, t.Img, t.Folder, t.Sort, t.Replacement, t.DisplayRoll}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return t.InsertObjects(tx)
} }
type TableResult struct { type TableResult struct {
@@ -28,3 +89,52 @@ type TableResult struct {
Stats Stats Stats Stats
Range []int Range []int
} }
func (t *TableResult) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO table_result (%s, id, type, img, description, name, weight, drawn)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`, data.fieldName)
}
func (t *TableResult) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
InsertWithCtxParallel(group, ctx, tx, t.Stats, InsertId[string]{id: t.ID, fieldName: "table_result_id"})
InsertSimpleSlice(tx, t.Range, &InsertId[string]{id: t.ID, fieldName: "table_result_id", tableName: "table_result_range"})
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (t *TableResult) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.ID, t.Type, t.Img, t.Description, t.Name, t.Weight, t.Drawn}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return t.InsertObjects(tx)
}
func (t *TableResult) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.ID, t.Type, t.Img, t.Description, t.Name, t.Weight, t.Drawn}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return t.InsertObjects(tx)
}

View File

@@ -62,3 +62,40 @@ type SystemUpdate struct {
HasUpdate bool HasUpdate bool
Version string Version string
} }
func (s *SystemUpdate) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO system_update (%s, has_update, version)
VALUES ($1, $2, $3)
RETURNING id`, data.fieldName)
}
func (s *SystemUpdate) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.HasUpdate, s.Version}
err := tx.QueryRowx(data.query, args...).Scan(&s.ID)
if err != nil {
return err
}
return nil
}
func (s *SystemUpdate) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.HasUpdate, s.Version}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&s.ID)
if err != nil {
return err
}
return nil
}

View File

@@ -1,5 +1,14 @@
package db package db
import (
"context"
"database/sql"
"errors"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type User struct { type User struct {
ID string ID string
@@ -13,9 +22,95 @@ type User struct {
Hotbar []UserHotbar Hotbar []UserHotbar
} }
func (u *User) Query(data *InsertId[uint]) {
data.query = `
INSERT INTO user (game_id, id, name, avatar, character, color, pronouns, role)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`
}
func (u *User) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[string]{id: u.ID, fieldName: "user_id"}
InsertWithCtxParallel(group, ctx, tx, u.Stats, relId)
InsertSliceParallel(group, tx, u.Hotbar, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (u *User) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, u.ID, u.Name, u.Avatar, u.Character, u.Color, u.Pronouns, u.Role}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return nil
}
func (u *User) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, u.ID, u.Name, u.Avatar, u.Character, u.Color, u.Pronouns, u.Role}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return nil
}
type UserHotbar struct { type UserHotbar struct {
ID uint ID uint
Key int Key int
Value string Value string
} }
func (u UserHotbar) Query(data *InsertId[string]) {
data.query = `
INSERT INTO hotbar (user_id, id, key_, value)
VALUES ($1, $2, $3, $4)`
}
func (u UserHotbar) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, u.ID, u.Key, u.Value}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return nil
}
func (u UserHotbar) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, u.ID, u.Key, u.Value}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return nil
}

View File

@@ -4,14 +4,15 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"sync"
"time" "time"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
) )
var ( var (
ErrNoQuery = errors.New("Query has not been set") ErrNoQuery = errors.New("Query has not been set")
ErrorRecordNotFound = errors.New("Record not found")
) )
type AllowedIds interface { type AllowedIds interface {
@@ -25,75 +26,40 @@ type InsertId[T AllowedIds] struct {
query string query string
} }
type SyncDB struct {
errChan chan error
wg sync.WaitGroup
}
func NewSyncDB() *SyncDB {
return &SyncDB{
wg: sync.WaitGroup{},
errChan: make(chan error),
}
}
func (s *SyncDB) Wait() error {
return WaitSync(&s.wg, s.errChan)
}
func WaitSync(wg *sync.WaitGroup, errChan chan error) error {
wgDone := make(chan struct{})
go func() {
wg.Wait()
close(wgDone)
}()
select {
case <-wgDone:
return nil
case err := <-errChan:
close(wgDone)
return err
}
}
type Insertable[T AllowedIds] interface { type Insertable[T AllowedIds] interface {
Query(data *InsertId[T]) Query(data *InsertId[T])
Insert(tx *sqlx.Tx, relId *InsertId[T]) error Insert(tx *sqlx.Tx, relId *InsertId[T]) error
InsertCtx(ctx context.Context, tx *sqlx.Tx, relId *InsertId[T]) error InsertCtx(ctx context.Context, tx *sqlx.Tx, relId *InsertId[T]) error
} }
func InsertWithCtx[T AllowedIds, I Insertable[T]](tx *sqlx.Tx, data I, relId *InsertId[T]) error { func InsertWithCtx[T AllowedIds, I Insertable[T]](tx *sqlx.Tx, data I, relId InsertId[T]) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
data.Query(relId) data.Query(&relId)
return data.InsertCtx(ctx, tx, relId) return data.InsertCtx(ctx, tx, &relId)
} }
func InsertWithCtxParallel[T AllowedIds, I Insertable[T]](syncDb *SyncDB, tx *sqlx.Tx, data I, relId *InsertId[T]) { func InsertWithCtxParallel[T AllowedIds, I Insertable[T]](g *errgroup.Group, ctx context.Context, tx *sqlx.Tx, data I, relId InsertId[T]) {
syncDb.wg.Go(func() { g.Go(func() error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
data.Query(relId) data.Query(&relId)
err := data.InsertCtx(ctx, tx, relId) err := data.InsertCtx(ctx, tx, &relId)
if err != nil { return err
syncDb.errChan <- err
}
}) })
} }
func InsertSlice[T AllowedIds, I Insertable[T]](tx *sqlx.Tx, data []I, relId *InsertId[T]) error { func InsertSlice[T AllowedIds, I Insertable[T]](tx *sqlx.Tx, data []I, relId InsertId[T]) error {
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel() defer cancel()
if len(data) > 0 { if len(data) > 0 {
data[0].Query(relId) data[0].Query(&relId)
} }
for i := range data { for i := range data {
err := data[i].InsertCtx(ctx, tx, relId) err := data[i].InsertCtx(ctx, tx, &relId)
if err != nil { if err != nil {
return err return err
} }
@@ -101,32 +67,25 @@ func InsertSlice[T AllowedIds, I Insertable[T]](tx *sqlx.Tx, data []I, relId *In
return nil return nil
} }
func InsertSliceParallel[T AllowedIds, I Insertable[T]](syncDb *SyncDB, tx *sqlx.Tx, data []I, relId *InsertId[T]) { func InsertSliceParallel[T AllowedIds, I Insertable[T]](g *errgroup.Group, tx *sqlx.Tx, data []I, relId InsertId[T]) {
syncDb.wg.Go(func() { g.Go(func() error {
wg := sync.WaitGroup{} wg, _ := errgroup.WithContext(context.Background())
errChan := make(chan error)
defer close(errChan)
var err error var err error
if len(data) > 0 { if len(data) > 0 {
data[0].Query(relId) data[0].Query(&relId)
} }
for i := range data { for i := range data {
wg.Go(func() { wg.Go(func() error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
err = data[i].InsertCtx(ctx, tx, relId) err = data[i].InsertCtx(ctx, tx, &relId)
if err != nil { return err
errChan <- err
}
}) })
} }
err = WaitSync(&wg, errChan) return wg.Wait()
if err != nil {
syncDb.errChan <- err
}
}) })
} }
@@ -147,30 +106,69 @@ func InsertSimpleSlice[T AllowedIds, I any](tx *sqlx.Tx, data []I, relId *Insert
return nil return nil
} }
func InsertSimpleSliceParallel[T AllowedIds, I any](syncDb *SyncDB, tx *sqlx.Tx, data []I, relId *InsertId[T]) { func InsertSimpleSliceParallel[T AllowedIds, I any](g *errgroup.Group, tx *sqlx.Tx, data []I, relId *InsertId[T]) {
syncDb.wg.Go(func() { g.Go(func() error {
wg := sync.WaitGroup{} wg, _ := errgroup.WithContext(context.Background())
errChan := make(chan error)
defer close(errChan)
query := fmt.Sprintf(` query := fmt.Sprintf(`
INSERT INTO %s (%s, value) INSERT INTO %s (%s, value)
VALUES ($1, $2)`, relId.tableName, relId.fieldName) VALUES ($1, $2)`, relId.tableName, relId.fieldName)
for i := range data { for i := range data {
wg.Go(func() { wg.Go(func() error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
_, err := tx.ExecContext(ctx, query, relId.id, data[i]) _, err := tx.ExecContext(ctx, query, relId.id, data[i])
if err != nil { return err
errChan <- err
}
}) })
} }
err := WaitSync(&wg, errChan) return wg.Wait()
if err != nil {
syncDb.errChan <- err
}
}) })
} }
func DeleteAll(db *sqlx.DB) error {
query := `
DELETE FROM setup`
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
result, err := db.ExecContext(ctx, query)
if err != nil {
return err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return err
}
if rowsAffected == 0 {
return ErrorRecordNotFound
}
return nil
}
func DeleteAllSeq(db *sqlx.DB) error {
query := `
DELETE FROM sqlite_sequence`
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
result, err := db.ExecContext(ctx, query)
if err != nil {
return err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return err
}
if rowsAffected == 0 {
return ErrorRecordNotFound
}
return nil
}

View File

@@ -2,10 +2,13 @@ package db
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt" "fmt"
"time" "time"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
) )
type World struct { type World struct {
@@ -53,28 +56,31 @@ func (w *World) Query(data *InsertId[string]) {
} }
func (w *World) InsertObjects(tx *sqlx.Tx) error { func (w *World) InsertObjects(tx *sqlx.Tx) error {
relId := &InsertId[string]{id: w.ID, fieldName: "world_id"} relId := InsertId[string]{id: w.ID, fieldName: "world_id"}
syncDB := NewSyncDB() group, ctx := errgroup.WithContext(context.Background())
defer close(syncDB.errChan)
InsertWithCtxParallel(syncDB, tx, w.Compatibility, relId) InsertWithCtxParallel(group, ctx, tx, w.Compatibility, relId)
InsertWithCtxParallel(syncDB, tx, w.Relationships, relId) InsertWithCtxParallel(group, ctx, tx, w.Relationships, relId)
esModulesRelId := &InsertId[string]{id: w.ID, fieldName: "world_id", tableName: "es_modules"} esModulesRelId := &InsertId[string]{id: w.ID, fieldName: "world_id", tableName: "es_modules"}
InsertSimpleSliceParallel(syncDB, tx, w.Esmodules, esModulesRelId) InsertSimpleSliceParallel(group, tx, w.Esmodules, esModulesRelId)
scriptRelId := &InsertId[string]{id: w.ID, fieldName: "world_id", tableName: "scripts"} scriptRelId := &InsertId[string]{id: w.ID, fieldName: "world_id", tableName: "scripts"}
InsertSimpleSliceParallel(syncDB, tx, w.Scripts, scriptRelId) InsertSimpleSliceParallel(group, tx, w.Scripts, scriptRelId)
tagsRelId := &InsertId[string]{id: w.ID, fieldName: "world_id", tableName: "tags"} tagsRelId := &InsertId[string]{id: w.ID, fieldName: "world_id", tableName: "tags"}
InsertSimpleSliceParallel(syncDB, tx, w.Tags, tagsRelId) InsertSimpleSliceParallel(group, tx, w.Tags, tagsRelId)
InsertSliceParallel(syncDB, tx, w.Authors, relId) InsertSliceParallel(group, tx, w.Authors, relId)
InsertSliceParallel(syncDB, tx, w.Media, relId) InsertSliceParallel(group, tx, w.Media, relId)
InsertSliceParallel(syncDB, tx, w.Styles, relId) InsertSliceParallel(group, tx, w.Styles, relId)
InsertSliceParallel(syncDB, tx, w.Languages, relId) InsertSliceParallel(group, tx, w.Languages, relId)
InsertSliceParallel(syncDB, tx, w.Packs, relId) InsertSliceParallel(group, tx, w.Packs, relId)
InsertSliceParallel(syncDB, tx, w.PackFolders, relId) InsertSliceParallel(group, tx, w.PackFolders, relId)
return syncDB.Wait() 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 { func (w *World) Insert(tx *sqlx.Tx, data *InsertId[string]) error {

View File

@@ -21,27 +21,31 @@ type CardDeck struct {
// Cards0System any `json:"system"` // Cards0System any `json:"system"`
} }
func (c *CardDeck) ToDB(dest *db.CardDeck) bool { func (c *CardDeck) ToDB(dest **db.CardDeck) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.Name = c.Name cardDeck := &db.CardDeck{
dest.Type = c.Type Name: c.Name,
dest.Description = c.Description Type: c.Type,
dest.Img = c.Img Description: c.Description,
dest.Width = c.Width Img: c.Img,
dest.Height = c.Height Width: c.Width,
dest.Rotation = c.Rotation Height: c.Height,
dest.DisplayCount = c.DisplayCount Rotation: c.Rotation,
dest.Folder = c.Folder DisplayCount: c.DisplayCount,
dest.Sort = c.Sort Folder: c.Folder,
dest.ID = c.ID Sort: c.Sort,
ID: c.ID,
}
c.Stats.ToDB(&dest.Stats) c.Stats.ToDB(&cardDeck.Stats)
c.Ownership.ToDB(&dest.Ownership) c.Ownership.ToDB(&cardDeck.Ownership)
CopySliceToDB(&dest.Cards, c.Cards) CopySliceToDB(&cardDeck.Cards, c.Cards)
*dest = cardDeck
return true return true
} }
@@ -67,29 +71,33 @@ type Card struct {
// System any `json:"system"` // System any `json:"system"`
} }
func (c *Card) ToDB(dest *db.Card) bool { func (c *Card) ToDB(dest **db.Card) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.Name = c.Name card := &db.Card{
dest.Width = c.Width Name: c.Name,
dest.Height = c.Height Width: c.Width,
dest.Rotation = c.Rotation Height: c.Height,
dest.Type = c.Type Rotation: c.Rotation,
dest.Value = c.Value Type: c.Type,
dest.Suit = c.Suit Value: c.Value,
dest.Description = c.Description Suit: c.Suit,
dest.Face = c.Face Description: c.Description,
dest.Drawn = c.Drawn Face: c.Face,
dest.Origin = c.Origin Drawn: c.Drawn,
dest.ID = c.ID Origin: c.Origin,
dest.Sort = c.Sort ID: c.ID,
Sort: c.Sort,
}
c.Back.ToDB(&dest.Back) c.Back.ToDB(&card.Back)
c.Stats.ToDB(&dest.Stats) c.Stats.ToDB(&card.Stats)
CopySliceToDB(&dest.Faces, c.Faces) CopySliceToDB(&card.Faces, c.Faces)
*dest = card
return true return true
} }

View File

@@ -17,23 +17,28 @@ type Combat struct {
// Flags any `json:"flags"` // Flags any `json:"flags"`
} }
func (c *Combat) ToDB(dest *db.Combat) bool { func (c *Combat) ToDB(dest **db.Combat) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.ID = c.Id combat := &db.Combat{
dest.Type = c.Type ID: c.Id,
dest.Scene = c.Scene Type: c.Type,
dest.Active = c.Active Scene: c.Scene,
dest.Round = c.Round Active: c.Active,
dest.Turn = c.Turn Round: c.Round,
dest.Sort = c.Sort Turn: c.Turn,
Sort: c.Sort,
}
c.Stats.ToDB(&dest.Stats) c.Stats.ToDB(&combat.Stats)
copy(dest.Groups, c.Groups) combat.Groups = make([]string, len(c.Groups))
CopySliceToDB(&dest.Combatants, c.Combatants) copy(combat.Groups, c.Groups)
CopySliceToDB(&combat.Combatants, c.Combatants)
*dest = combat
return true return true
} }
@@ -54,22 +59,27 @@ type Combatant struct {
// Flags any `json:"flags"` // Flags any `json:"flags"`
} }
func (c *Combatant) ToDB(dest *db.Combatant) bool { func (c *Combatant) ToDB(dest **db.Combatant) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.TokenId = c.TokenId combatant := &db.Combatant{
dest.SceneId = c.SceneId TokenId: c.TokenId,
dest.ActorId = c.ActorId SceneId: c.SceneId,
dest.Hidden = c.Hidden ActorId: c.ActorId,
dest.ID = c.Id Hidden: c.Hidden,
dest.Type = c.Type ID: c.Id,
dest.Img = c.Img Type: c.Type,
dest.Initiative = c.Initiative Img: c.Img,
dest.Defeated = c.Defeated Initiative: c.Initiative,
dest.Group = c.Group Defeated: c.Defeated,
c.Stats.ToDB(&dest.Stats) Group: c.Group,
}
c.Stats.ToDB(&combatant.Stats)
*dest = combatant
return true return true
} }

View File

@@ -15,11 +15,11 @@ func (d *DocumentTypes) ToDB(dest *db.DocumentTypes) bool {
dest.Data = make([]*db.DocumentTypeData, 2) dest.Data = make([]*db.DocumentTypeData, 2)
dest.Data[0] = &db.DocumentTypeData{Type: "Actor"}
d.Actor.ToDB(dest.Data[0]) d.Actor.ToDB(dest.Data[0])
dest.Data[0].Type = "Actor"
dest.Data[1] = &db.DocumentTypeData{Type: "Item"}
d.Item.ToDB(dest.Data[1]) d.Item.ToDB(dest.Data[1])
dest.Data[1].Type = "Item"
return true return true
} }

View File

@@ -20,6 +20,8 @@ func (f *Folder) ToDB(dest **db.Folder) bool {
Sorting: f.Sorting, Sorting: f.Sorting,
Color: f.Color, Color: f.Color,
} }
folder.Packs = make([]string, len(f.Packs))
copy(folder.Packs, f.Packs) copy(folder.Packs, f.Packs)
CopySliceToDB(&folder.Folders, f.Folders) CopySliceToDB(&folder.Folders, f.Folders)
@@ -41,20 +43,25 @@ type WorldFolder struct {
// Flags any `json:"flags,omitempty"` // Flags any `json:"flags,omitempty"`
} }
func (w *WorldFolder) ToDB(dest *db.WorldFolder) bool { func (w *WorldFolder) ToDB(dest **db.WorldFolder) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.Name = w.Name worldFolder := &db.WorldFolder{
dest.Type = w.Type Name: w.Name,
dest.ID = w.ID Type: w.Type,
dest.Folder = w.Folder ID: w.ID,
dest.Sorting = w.Sorting Folder: w.Folder,
dest.Sort = w.Sort Sorting: w.Sorting,
w.Stats.ToDB(&dest.Stats) Sort: w.Sort,
dest.Description = w.Description Description: w.Description,
dest.Color = w.Color Color: w.Color,
}
w.Stats.ToDB(&worldFolder.Stats)
*dest = worldFolder
return true return true
} }

View File

@@ -55,23 +55,25 @@ func (g *Game) ToDB(dest *db.Game) bool {
g.Options.ToDB(&dest.Options) g.Options.ToDB(&dest.Options)
g.CoreUpdate.ToDB(&dest.CoreUpdate) g.CoreUpdate.ToDB(&dest.CoreUpdate)
g.SystemUpdate.ToDB(&dest.SystemUpdate) g.SystemUpdate.ToDB(&dest.SystemUpdate)
dest.ActiveUsers = make([]string, len(g.ActiveUsers))
copy(dest.ActiveUsers, g.ActiveUsers) copy(dest.ActiveUsers, g.ActiveUsers)
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
go CopySliceToDBParallel(&wg, &dest.Modules, g.Modules) CopySliceToDBParallel(&wg, &dest.Modules, g.Modules)
go CopySliceToDBParallel(&wg, &dest.Packs, g.Packs) CopySliceToDBParallel(&wg, &dest.Packs, g.Packs)
go CopySliceToDBParallel(&wg, &dest.Messages, g.Messages) CopySliceToDBParallel(&wg, &dest.Messages, g.Messages)
go CopySliceToDBParallel(&wg, &dest.Combats, g.Combats) CopySliceToDBParallel(&wg, &dest.Combats, g.Combats)
go CopySliceToDBParallel(&wg, &dest.CardDeck, g.CardDeck) CopySliceToDBParallel(&wg, &dest.CardDeck, g.CardDeck)
go CopySliceToDBParallel(&wg, &dest.Users, g.Users) CopySliceToDBParallel(&wg, &dest.Users, g.Users)
go CopySliceToDBParallel(&wg, &dest.Macros, g.Macros) CopySliceToDBParallel(&wg, &dest.Macros, g.Macros)
go CopySliceToDBParallel(&wg, &dest.Folders, g.Folders) CopySliceToDBParallel(&wg, &dest.Folders, g.Folders)
go CopySliceToDBParallel(&wg, &dest.Items, g.Items) CopySliceToDBParallel(&wg, &dest.Items, g.Items)
go CopySliceToDBParallel(&wg, &dest.Settings, g.Settings) CopySliceToDBParallel(&wg, &dest.Settings, g.Settings)
go CopySliceToDBParallel(&wg, &dest.Journals, g.Journals) CopySliceToDBParallel(&wg, &dest.Journals, g.Journals)
go CopySliceToDBParallel(&wg, &dest.Tables, g.Tables) CopySliceToDBParallel(&wg, &dest.Tables, g.Tables)
go CopySliceToDBParallel(&wg, &dest.Playlists, g.Playlists) CopySliceToDBParallel(&wg, &dest.Playlists, g.Playlists)
go CopySliceToDBParallel(&wg, &dest.Actors, g.Actors) CopySliceToDBParallel(&wg, &dest.Actors, g.Actors)
// go CopySliceToDBParallel(&wg, &dest.Scenes, g.Scenes) // go CopySliceToDBParallel(&wg, &dest.Scenes, g.Scenes)
wg.Wait() wg.Wait()

View File

@@ -16,19 +16,23 @@ type Item struct {
// Effects []any `json:"effects"` // Effects []any `json:"effects"`
} }
func (i *Item) ToDB(dest *db.Item) bool { func (i *Item) ToDB(dest **db.Item) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.Img = i.Img item := &db.Item{
dest.Name = i.Name Img: i.Img,
dest.Type = i.Type Name: i.Name,
dest.Folder = i.Folder Type: i.Type,
dest.ID = i.ID Folder: i.Folder,
dest.Sort = i.Sort ID: i.ID,
Sort: i.Sort,
}
i.Stats.ToDB(&dest.Stats) i.Stats.ToDB(&item.Stats)
*dest = item
return true return true
} }

View File

@@ -14,17 +14,21 @@ type Journal struct {
// Categories []any `json:"categories"` // Categories []any `json:"categories"`
} }
func (j *Journal) ToDB(dest *db.Journal) bool { func (j *Journal) ToDB(dest **db.Journal) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.Name = j.Name journal := &db.Journal{
dest.Sort = j.Sort Name: j.Name,
dest.ID = j.ID Sort: j.Sort,
ID: j.ID,
}
OwnershipToDB(&dest.Ownership, j.Ownership) OwnershipToDB(&journal.Ownership, j.Ownership)
CopySliceToDB(&dest.Pages, j.Pages) CopySliceToDB(&journal.Pages, j.Pages)
*dest = journal
return true return true
} }

View File

@@ -19,23 +19,25 @@ type JournalPage struct {
// Category any `json:"category"` // Category any `json:"category"`
} }
func (j *JournalPage) ToDB(dest *db.JournalPage) bool { func (j *JournalPage) ToDB(dest **db.JournalPage) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.Name = j.Name journalPage := &db.JournalPage{
dest.Type = j.Type Name: j.Name,
dest.ID = j.ID Type: j.Type,
dest.Src = j.Src ID: j.ID,
dest.Sort = j.Sort Src: j.Src,
Sort: j.Sort,
}
j.Text.ToDB(&dest.Text) j.Text.ToDB(&journalPage.Text)
j.Title.ToDB(&dest.Title) j.Title.ToDB(&journalPage.Title)
j.Video.ToDB(&dest.Video) j.Video.ToDB(&journalPage.Video)
j.Stats.ToDB(&dest.Stats) j.Stats.ToDB(&journalPage.Stats)
OwnershipToDB(&dest.Ownership, j.Ownership) OwnershipToDB(&journalPage.Ownership, j.Ownership)
return true return true
} }

View File

@@ -17,24 +17,28 @@ type Macro struct {
// Flags any `json:"flags,omitempty"` // Flags any `json:"flags,omitempty"`
} }
func (m *Macro) ToDB(dest *db.Macro) bool { func (m *Macro) ToDB(dest **db.Macro) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.Command = m.Command macro := &db.Macro{
dest.Name = m.Name Command: m.Command,
dest.Type = m.Type Name: m.Name,
dest.Img = m.Img Type: m.Type,
dest.ID = m.ID Img: m.Img,
dest.Author = m.Author ID: m.ID,
dest.Scope = m.Scope Author: m.Author,
dest.Folder = m.Folder Scope: m.Scope,
dest.Sort = m.Sort Folder: m.Folder,
Sort: m.Sort,
}
m.Stats.ToDB(&dest.Stats) m.Stats.ToDB(&macro.Stats)
OwnershipToDB(&dest.Ownership, m.Ownership) OwnershipToDB(&macro.Ownership, m.Ownership)
*dest = macro
return true return true
} }

View File

@@ -21,27 +21,33 @@ type Message struct {
// Flags any `json:"flags"` // Flags any `json:"flags"`
} }
func (m *Message) ToDB(dest *db.Message) bool { func (m *Message) ToDB(dest **db.Message) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.Content = m.Content message := &db.Message{
dest.Style = m.Style Content: m.Content,
dest.Author = m.Author Style: m.Style,
dest.ID = m.Id Author: m.Author,
dest.Type = m.Type ID: m.Id,
dest.Timestamp = m.Timestamp Type: m.Type,
dest.Flavor = m.Flavor Timestamp: m.Timestamp,
dest.Blind = m.Blind Flavor: m.Flavor,
dest.Sound = m.Sound Blind: m.Blind,
dest.Emote = m.Emote Sound: m.Sound,
Emote: m.Emote,
}
m.Speaker.ToDB(&dest.Speaker) m.Speaker.ToDB(&message.Speaker)
m.Stats.ToDB(&dest.Stats) m.Stats.ToDB(&message.Stats)
copy(dest.Whisper, m.Whisper) message.Whisper = make([]string, len(m.Whisper))
copy(dest.Rolls, m.Rolls) copy(message.Whisper, m.Whisper)
message.Rolls = make([]string, len(m.Rolls))
copy(message.Rolls, m.Rolls)
*dest = message
return true return true
} }

View File

@@ -74,8 +74,11 @@ func (m *Module) ToDB(dest **db.Module) bool {
Active: m.Active, Active: m.Active,
} }
module.Scripts = make([]string, len(m.Scripts))
copy(module.Scripts, m.Scripts) copy(module.Scripts, m.Scripts)
module.Esmodules = make([]string, len(m.Esmodules))
copy(module.Esmodules, m.Esmodules) copy(module.Esmodules, m.Esmodules)
module.Tags = make([]string, len(m.Tags))
copy(module.Tags, m.Tags) copy(module.Tags, m.Tags)
m.Compatibility.ToDB(&module.Compatibility) m.Compatibility.ToDB(&module.Compatibility)
@@ -83,12 +86,12 @@ func (m *Module) ToDB(dest **db.Module) bool {
m.DocumentTypes.ToDB(&module.DocumentTypes) m.DocumentTypes.ToDB(&module.DocumentTypes)
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
go CopySliceToDBParallel(&wg, &module.Authors, m.Authors) CopySliceToDBParallel(&wg, &module.Authors, m.Authors)
go CopySliceToDBParallel(&wg, &module.Media, m.Media) CopySliceToDBParallel(&wg, &module.Media, m.Media)
go CopySliceToDBParallel(&wg, &module.Styles, m.Styles) CopySliceToDBParallel(&wg, &module.Styles, m.Styles)
go CopySliceToDBParallel(&wg, &module.Languages, m.Languages) CopySliceToDBParallel(&wg, &module.Languages, m.Languages)
go CopySliceToDBParallel(&wg, &module.Packs, m.Packs) CopySliceToDBParallel(&wg, &module.Packs, m.Packs)
go CopySliceToDBParallel(&wg, &module.PackFolders, m.PackFolders) CopySliceToDBParallel(&wg, &module.PackFolders, m.PackFolders)
wg.Wait() wg.Wait()
*dest = module *dest = module

View File

@@ -36,14 +36,14 @@ func (p *Pack) ToDB(dest **db.Pack) bool {
System: p.System, System: p.System,
PackageType: p.PackageType, PackageType: p.PackageType,
PackageName: p.PackageName, PackageName: p.PackageName,
ID: p.Id, Key: p.Id,
} }
p.Ownership.ToDB(&pack.Ownership) p.Ownership.ToDB(&pack.Ownership)
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
go CopySliceToDBParallel(&wg, &pack.Index, p.Index) CopySliceToDBParallel(&wg, &pack.Index, p.Index)
go CopySliceToDBParallel(&wg, &pack.Folders, p.Folders) CopySliceToDBParallel(&wg, &pack.Folders, p.Folders)
wg.Wait() wg.Wait()
*dest = pack *dest = pack

View File

@@ -11,18 +11,25 @@ type PackageWarningsData struct {
Manifest string `json:"manifest,omitempty"` Manifest string `json:"manifest,omitempty"`
} }
func (p *PackageWarningsData) ToDB(dest *db.PackageWarningsData) bool { func (p *PackageWarningsData) ToDB(dest **db.PackageWarningsData) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.ID = p.Id packageData := &db.PackageWarningsData{
dest.Type = p.Type ID: p.Id,
dest.Reinstallable = p.Reinstallable Type: p.Type,
dest.Manifest = p.Manifest Reinstallable: p.Reinstallable,
Manifest: p.Manifest,
}
copy(dest.Warning, p.Warning) packageData.Warning = make([]string, len(p.Warning))
copy(dest.Error, p.Error) copy(packageData.Warning, p.Warning)
packageData.Error = make([]string, len(p.Error))
copy(packageData.Error, p.Error)
*dest = packageData
return true return true
} }

View File

@@ -20,28 +20,30 @@ type Playlist struct {
// Flags any `json:"flags,omitempty"` // Flags any `json:"flags,omitempty"`
} }
func (p *Playlist) ToDB(dest *db.Playlist) bool { func (p *Playlist) ToDB(dest **db.Playlist) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.Name = p.Name playlist := &db.Playlist{
dest.ID = p.ID Name: p.Name,
dest.Mode = p.Mode ID: p.ID,
dest.Playing = p.Playing Mode: p.Mode,
dest.Fade = p.Fade Playing: p.Playing,
dest.Folder = p.Folder Fade: p.Fade,
dest.Sorting = p.Sorting Folder: p.Folder,
dest.Seed = p.Seed Sorting: p.Sorting,
dest.Sort = p.Sort Seed: p.Seed,
dest.Description = p.Description Sort: p.Sort,
dest.Channel = p.Channel Description: p.Description,
Channel: p.Channel,
}
p.Stats.ToDB(&dest.Stats) p.Stats.ToDB(&playlist.Stats)
OwnershipToDB(&dest.Ownership, p.Ownership) OwnershipToDB(&playlist.Ownership, p.Ownership)
CopySliceToDB(&dest.Sounds, p.Sounds) CopySliceToDB(&playlist.Sounds, p.Sounds)
return true return true
} }
@@ -61,22 +63,26 @@ type Sound struct {
// Flags any `json:"flags"` // Flags any `json:"flags"`
} }
func (s *Sound) ToDB(dest *db.Sound) bool { func (s *Sound) ToDB(dest **db.Sound) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.Name = s.Name sound := &db.Sound{
dest.Path = s.Path Name: s.Name,
dest.ID = s.ID Path: s.Path,
dest.Playing = s.Playing ID: s.ID,
dest.PausedTime = s.PausedTime Playing: s.Playing,
dest.Repeat = s.Repeat PausedTime: s.PausedTime,
dest.Volume = s.Volume Repeat: s.Repeat,
dest.Fade = s.Fade Volume: s.Volume,
dest.Sort = s.Sort Fade: s.Fade,
dest.Channel = s.Channel Sort: s.Sort,
dest.Description = s.Description Channel: s.Channel,
Description: s.Description,
}
*dest = sound
return true return true
} }

View File

@@ -20,10 +20,10 @@ func (r *Relationships) ToDB(dest *db.Relationships) bool {
} }
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
go CopySliceToDBParallel(&wg, &dest.Systems, r.Systems) CopySliceToDBParallel(&wg, &dest.Systems, r.Systems)
go CopySliceToDBParallel(&wg, &dest.Requires, r.Requires) CopySliceToDBParallel(&wg, &dest.Requires, r.Requires)
go CopySliceToDBParallel(&wg, &dest.Recommends, r.Recommends) CopySliceToDBParallel(&wg, &dest.Recommends, r.Recommends)
go CopySliceToDBParallel(&wg, &dest.Conflicts, r.Conflicts) CopySliceToDBParallel(&wg, &dest.Conflicts, r.Conflicts)
wg.Wait() wg.Wait()
return true return true
@@ -41,7 +41,7 @@ func (r *RelationshipsData) ToDB(dest *db.RelationshipsData) bool {
return false return false
} }
dest.ID = r.Id dest.Key = r.Id
dest.Type = r.Type dest.Type = r.Type
dest.Manifest = r.Manifest dest.Manifest = r.Manifest

View File

@@ -85,12 +85,12 @@ func (s *Scene) ToDB(dest *db.Scene) bool {
OwnershipToDB(&dest.Ownership, s.Ownership) OwnershipToDB(&dest.Ownership, s.Ownership)
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
go CopySliceToDBParallel(&wg, &dest.Drawings, s.Drawings) CopySliceToDBParallel(&wg, &dest.Drawings, s.Drawings)
go CopySliceToDBParallel(&wg, &dest.Tokens, s.Tokens) CopySliceToDBParallel(&wg, &dest.Tokens, s.Tokens)
go CopySliceToDBParallel(&wg, &dest.Lights, s.Lights) CopySliceToDBParallel(&wg, &dest.Lights, s.Lights)
go CopySliceToDBParallel(&wg, &dest.Notes, s.Notes) CopySliceToDBParallel(&wg, &dest.Notes, s.Notes)
go CopySliceToDBParallel(&wg, &dest.Sounds, s.Sounds) CopySliceToDBParallel(&wg, &dest.Sounds, s.Sounds)
go CopySliceToDBParallel(&wg, &dest.Walls, s.Walls) CopySliceToDBParallel(&wg, &dest.Walls, s.Walls)
wg.Wait() wg.Wait()
return true return true

View File

@@ -10,15 +10,20 @@ type Setting struct {
Stats Stats `json:"_stats"` Stats Stats `json:"_stats"`
} }
func (s *Setting) ToDB(dest *db.Setting) bool { func (s *Setting) ToDB(dest **db.Setting) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.Key = s.Key setting := &db.Setting{
dest.Value = s.Value Key: s.Key,
dest.ID = s.ID Value: s.Value,
s.Stats.ToDB(&dest.Stats) ID: s.ID,
}
s.Stats.ToDB(&setting.Stats)
*dest = setting
return true return true
} }

View File

@@ -1,6 +1,7 @@
package json package json
import ( import (
"encoding/json"
"sync" "sync"
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/temp_models/db" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/temp_models/db"
@@ -22,6 +23,19 @@ type Setup struct {
Worlds []*World `json:"worlds"` Worlds []*World `json:"worlds"`
} }
func ParseSetup(data []byte) (*Setup, error) {
var modelSetup []Setup
err := json.Unmarshal(data, &modelSetup)
if err != nil {
return nil, err
}
if len(modelSetup) > 1 {
return nil, ErrorSetupMoreThanOne
}
return &modelSetup[0], nil
}
func (s *Setup) ToDB(dest *db.Setup) bool { func (s *Setup) ToDB(dest *db.Setup) bool {
if dest == nil { if dest == nil {
return false return false
@@ -39,11 +53,11 @@ func (s *Setup) ToDB(dest *db.Setup) bool {
PackageWarningsToDB(&dest.PackageWarnings, s.PackageWarnings) PackageWarningsToDB(&dest.PackageWarnings, s.PackageWarnings)
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
go CopySliceToDBParallel(&wg, &dest.Languages, s.Languages) CopySliceToDBParallel(&wg, &dest.Languages, s.Languages)
go CopySliceToDBParallel(&wg, &dest.Modules, s.Modules) CopySliceToDBParallel(&wg, &dest.Modules, s.Modules)
go CopySliceToDBParallel(&wg, &dest.News, s.News) CopySliceToDBParallel(&wg, &dest.News, s.News)
go CopySliceToDBParallel(&wg, &dest.Systems, s.Systems) CopySliceToDBParallel(&wg, &dest.Systems, s.Systems)
go CopySliceToDBParallel(&wg, &dest.Worlds, s.Worlds) CopySliceToDBParallel(&wg, &dest.Worlds, s.Worlds)
wg.Wait() wg.Wait()
return true return true

View File

@@ -71,8 +71,11 @@ func (s *System) ToDB(dest **db.System) bool {
HasStorage: s.HasStorage, HasStorage: s.HasStorage,
} }
system.Scripts = make([]string, len(s.Scripts))
copy(system.Scripts, s.Scripts) copy(system.Scripts, s.Scripts)
system.Esmodules = make([]string, len(s.Esmodules))
copy(system.Esmodules, s.Esmodules) copy(system.Esmodules, s.Esmodules)
system.Tags = make([]string, len(s.Tags))
copy(system.Tags, s.Tags) copy(system.Tags, s.Tags)
s.Compatibility.ToDB(&system.Compatibility) s.Compatibility.ToDB(&system.Compatibility)
@@ -81,12 +84,12 @@ func (s *System) ToDB(dest **db.System) bool {
s.Grid.ToDB(&system.Grid) s.Grid.ToDB(&system.Grid)
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
go CopySliceToDBParallel(&wg, &system.Authors, s.Authors) CopySliceToDBParallel(&wg, &system.Authors, s.Authors)
go CopySliceToDBParallel(&wg, &system.Media, s.Media) CopySliceToDBParallel(&wg, &system.Media, s.Media)
go CopySliceToDBParallel(&wg, &system.Styles, s.Styles) CopySliceToDBParallel(&wg, &system.Styles, s.Styles)
go CopySliceToDBParallel(&wg, &system.Languages, s.Languages) CopySliceToDBParallel(&wg, &system.Languages, s.Languages)
go CopySliceToDBParallel(&wg, &system.Packs, s.Packs) CopySliceToDBParallel(&wg, &system.Packs, s.Packs)
go CopySliceToDBParallel(&wg, &system.PackFolders, s.PackFolders) CopySliceToDBParallel(&wg, &system.PackFolders, s.PackFolders)
wg.Wait() wg.Wait()
*dest = system *dest = system

View File

@@ -18,26 +18,28 @@ type Table struct {
// TablesFlags any `json:"flags,omitempty"` // TablesFlags any `json:"flags,omitempty"`
} }
func (t *Table) ToDB(dest *db.Table) bool { func (t *Table) ToDB(dest **db.Table) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.Name = t.Name table := &db.Table{
dest.Description = t.Description Name: t.Name,
dest.Formula = t.Formula Description: t.Description,
dest.ID = t.ID Formula: t.Formula,
dest.Img = t.Img ID: t.ID,
dest.Replacement = t.Replacement Img: t.Img,
dest.DisplayRoll = t.DisplayRoll Replacement: t.Replacement,
dest.Folder = t.Folder DisplayRoll: t.DisplayRoll,
dest.Sort = t.Sort Folder: t.Folder,
Sort: t.Sort,
}
t.Stats.ToDB(&dest.Stats) t.Stats.ToDB(&table.Stats)
OwnershipToDB(&dest.Ownership, t.Ownership) OwnershipToDB(&table.Ownership, t.Ownership)
CopySliceToDB(&dest.Results, t.Results) CopySliceToDB(&table.Results, t.Results)
return true return true
} }
@@ -55,22 +57,27 @@ type TableResult struct {
// ResultsFlags any `json:"flags"` // ResultsFlags any `json:"flags"`
} }
func (t *TableResult) ToDB(dest *db.TableResult) bool { func (t *TableResult) ToDB(dest **db.TableResult) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.Type = t.Type tableResult := &db.TableResult{
dest.Weight = t.Weight Type: t.Type,
dest.Drawn = t.Drawn Weight: t.Weight,
dest.ID = t.ID Drawn: t.Drawn,
dest.Img = t.Img ID: t.ID,
dest.Description = t.Description Img: t.Img,
dest.Name = t.Name Description: t.Description,
Name: t.Name,
}
copy(dest.Range, t.Range) tableResult.Range = make([]int, len(t.Range))
copy(tableResult.Range, t.Range)
t.Stats.ToDB(&dest.Stats) t.Stats.ToDB(&tableResult.Stats)
*dest = tableResult
return true return true
} }

View File

@@ -16,22 +16,26 @@ type User struct {
// UsersFlags any `json:"flags,omitempty"` // UsersFlags any `json:"flags,omitempty"`
} }
func (u *User) ToDB(dest *db.User) bool { func (u *User) ToDB(dest **db.User) bool {
if dest == nil { if dest == nil {
return false return false
} }
dest.Name = u.Name user := &db.User{
dest.Role = u.Role Name: u.Name,
dest.ID = u.ID Role: u.Role,
dest.Avatar = u.Avatar ID: u.ID,
dest.Character = u.Character Avatar: u.Avatar,
dest.Color = u.Color Character: u.Character,
dest.Pronouns = u.Pronouns Color: u.Color,
Pronouns: u.Pronouns,
}
u.UsersStats.ToDB(&dest.Stats) u.UsersStats.ToDB(&user.Stats)
HotbarToDB(&dest.Hotbar, u.Hotbar) HotbarToDB(&user.Hotbar, u.Hotbar)
*dest = user
return true return true
} }

View File

@@ -1,11 +1,16 @@
package json package json
import ( import (
"errors"
"sync" "sync"
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/temp_models/db" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/temp_models/db"
) )
var (
ErrorSetupMoreThanOne = errors.New("More than one setup data")
)
func OwnershipToDB(dest *[]db.OwnershipString, src map[string]int) { func OwnershipToDB(dest *[]db.OwnershipString, src map[string]int) {
*dest = make([]db.OwnershipString, len(src)) *dest = make([]db.OwnershipString, len(src))
@@ -33,8 +38,8 @@ func PackageWarningsToDB(dest *[]*db.PackageWarning, src map[string]PackageWarni
i := 0 i := 0
for k, v := range src { for k, v := range src {
(*dest)[i].Key = k (*dest)[i] = &db.PackageWarning{Key: k}
v.ToDB((*dest)[i].Value) v.ToDB(&(*dest)[i].Value)
i++ i++
} }
} }
@@ -57,7 +62,7 @@ func CopySliceToDB[destType any, srcType CastableToDB[destType]](dest *[]destTyp
} }
func CopySliceToDBParallel[destType any, srcType CastableToDB[destType]](wg *sync.WaitGroup, dest *[]destType, src []srcType) { func CopySliceToDBParallel[destType any, srcType CastableToDB[destType]](wg *sync.WaitGroup, dest *[]destType, src []srcType) {
wg.Add(1) wg.Go(func() {
CopySliceToDB(dest, src) CopySliceToDB(dest, src)
wg.Done() })
} }

View File

@@ -32,6 +32,7 @@ func (w *Wall) ToDB(dest *db.Wall) bool {
dest.ID = w.ID dest.ID = w.ID
w.Threshold.ToDB(&dest.Threshold) w.Threshold.ToDB(&dest.Threshold)
dest.C = make([]int, len(w.C))
copy(dest.C, w.C) copy(dest.C, w.C)
return true return true

View File

@@ -71,20 +71,23 @@ func (w *World) ToDB(dest **db.World) bool {
HasStorage: w.HasStorage, HasStorage: w.HasStorage,
} }
world.Scripts = make([]string, len(w.Scripts))
copy(world.Scripts, w.Scripts) copy(world.Scripts, w.Scripts)
world.Esmodules = make([]string, len(w.Esmodules))
copy(world.Esmodules, w.Esmodules) copy(world.Esmodules, w.Esmodules)
world.Tags = make([]string, len(w.Tags))
copy(world.Tags, w.Tags) copy(world.Tags, w.Tags)
w.Compatibility.ToDB(&world.Compatibility) w.Compatibility.ToDB(&world.Compatibility)
w.Relationships.ToDB(&world.Relationships) w.Relationships.ToDB(&world.Relationships)
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
go CopySliceToDBParallel(&wg, &world.Authors, w.Authors) CopySliceToDBParallel(&wg, &world.Authors, w.Authors)
go CopySliceToDBParallel(&wg, &world.Media, w.Media) CopySliceToDBParallel(&wg, &world.Media, w.Media)
go CopySliceToDBParallel(&wg, &world.Styles, w.Styles) CopySliceToDBParallel(&wg, &world.Styles, w.Styles)
go CopySliceToDBParallel(&wg, &world.Languages, w.Languages) CopySliceToDBParallel(&wg, &world.Languages, w.Languages)
go CopySliceToDBParallel(&wg, &world.Packs, w.Packs) CopySliceToDBParallel(&wg, &world.Packs, w.Packs)
go CopySliceToDBParallel(&wg, &world.PackFolders, w.PackFolders) CopySliceToDBParallel(&wg, &world.PackFolders, w.PackFolders)
wg.Wait() wg.Wait()
*dest = world *dest = world

View File

@@ -1,9 +1,9 @@
package transport package transport
import ( import (
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/models/db"
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/models/json"
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/requests" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/requests"
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/temp_models/db"
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/temp_models/json"
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/types" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/types"
) )
@@ -14,22 +14,22 @@ func (tr *FoundryTransport) FillDBWithFoundryData() {
return return
} }
idState, err := tr.Models.FoundryState.GetIdByType(db.SetupState) // idState, err := tr.Models.FoundryState.GetIdByType(db.SetupState)
if err != nil { // if err != nil {
tr.ReadChan.Err() <- &types.FoundryError{Direction: types.WriterCode, Err: err, Type: types.DbCode} // tr.ReadChan.Err() <- &types.FoundryError{Direction: types.WriterCode, Err: err, Type: types.DbCode}
return // return
} // }
err = tr.InitWorldsData(idState) // err = tr.InitWorldsData(idState)
if err != nil { // if err != nil {
tr.ReadChan.Err() <- &types.FoundryError{Direction: types.WriterCode, Err: err, Type: types.DbCode} // tr.ReadChan.Err() <- &types.FoundryError{Direction: types.WriterCode, Err: err, Type: types.DbCode}
return // return
} // }
} }
func (tr *FoundryTransport) InitSetupData() error { func (tr *FoundryTransport) InitSetupData() error {
tr.Models.FoundryState.DeleteAll() db.DeleteAll(tr.DB)
tr.Models.FoundryState.DeleteAllSeq() db.DeleteAllSeq(tr.DB)
for k := range requests.PathToSetupState { for k := range requests.PathToSetupState {
err := tr.InsertJsonDataToDB(k) err := tr.InsertJsonDataToDB(k)
if err != nil { if err != nil {
@@ -51,48 +51,51 @@ func (tr *FoundryTransport) InsertJsonDataToDB(statePath string) error {
return err return err
} }
foundryStateJson, err := json.ParseSetupModel(msgJson) foundryStateJson, err := json.ParseSetup(msgJson)
if err != nil { if err != nil {
return err return err
} }
foundryStateDb := foundryStateJson.GetFoundryStateDB(requests.PathToSetupState[statePath]) tr.Logger.Info("Setup data received")
err = tr.Models.FoundryState.Insert(foundryStateDb)
var foundryStateDb db.Setup
foundryStateJson.ToDB(&foundryStateDb)
err = foundryStateDb.Insert(tr.DB)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }
func (tr *FoundryTransport) InitWorldsData(idState int64) error { // func (tr *FoundryTransport) InitWorldsData(idState int64) error {
worlds, err := tr.Models.FoundryState.GetWorlds(idState) // worlds, err := tr.Models.FoundryState.GetWorlds(idState)
if err != nil { // if err != nil {
return err // return err
} // }
tr.Logger.Debug("Worlds", "len", len(worlds)) // tr.Logger.Debug("Worlds", "len", len(worlds))
for i := range worlds { // for i := range worlds {
worldName := worlds[i].TextId // worldName := worlds[i].TextId
tr.InitWorldData(worldName) // tr.InitWorldData(worldName)
_, err = tr.Http.PostReturnToSetup() // _, err = tr.Http.PostReturnToSetup()
if err != nil { // if err != nil {
return err // return err
} // }
} // }
return nil // return nil
} // }
func (tr *FoundryTransport) InitWorldData(worldName string) error { // func (tr *FoundryTransport) InitWorldData(worldName string) error {
tr.Logger.Debug("World name", "name", worldName) // tr.Logger.Debug("World name", "name", worldName)
err := tr.LaunchWorld(worldName) // err := tr.LaunchWorld(worldName)
if err != nil { // if err != nil {
return err // return err
} // }
for k := range requests.PathToWorldState { // for k := range requests.PathToWorldState {
err := tr.InsertJsonDataToDB(k) // err := tr.InsertJsonDataToDB(k)
if err != nil { // if err != nil {
return err // return err
} // }
} // }
return nil // return nil
} // }

View File

@@ -5,7 +5,6 @@ import (
"sync" "sync"
"time" "time"
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/models/db"
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/requests" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/requests"
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/types" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/types"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
@@ -26,7 +25,8 @@ type FoundryTransport struct {
IsAuth bool IsAuth bool
IsLogin bool IsLogin bool
Models *db.Models // Models *db.Models
DB *sqlx.DB
IsDbInit bool IsDbInit bool
Logger *slog.Logger Logger *slog.Logger
@@ -47,7 +47,7 @@ func NewFoundryTransport(dbConn *sqlx.DB, logger *slog.Logger, httpConfig *reque
ReconnectNumMax: 1, ReconnectNumMax: 1,
ReconnectNum: 0, ReconnectNum: 0,
Models: db.NewModels(dbConn), DB: dbConn,
IsDbInit: false, IsDbInit: false,
Logger: logger, Logger: logger,