package db import ( "context" "database/sql" "errors" "time" ) type World struct { Id int64 TextId string Title string Description string System string CoreVersion string SystemVersion string LastPlayed string PlayTime int64 NextSession time.Time CreatedAt time.Time Compatibility Compatibility } type Worlds []World func (worlds Worlds) GetById(id int) *World { return &worlds[id] } func (m FoundryStateModel) InsertWorld(world *World, stateId int64) error { query := ` INSERT INTO worlds (state_id, text_id, title, description, system, core_version, system_version, playtime, next_session) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id, created_at` args := []any{stateId, world.TextId, world.Title, world.Description, world.System, world.CoreVersion, world.SystemVersion, world.PlayTime, world.NextSession} ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() err := m.DB.QueryRowContext(ctx, query, args...).Scan(&world.Id, &world.CreatedAt) if err != nil && err != sql.ErrNoRows { return err } return m.InsertWorldCompatibility(&world.Compatibility, world.Id) } func (m FoundryStateModel) InsertWorldCompatibility(compatibility *Compatibility, worldId int64) error { query := ` INSERT INTO worlds_compatibility (world_id, minimum, verified, maximum) VALUES ($1, $2, $3, $4) RETURNING id` args := []any{worldId, compatibility.Minimum, compatibility.Verified, compatibility.Maximum} ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() err := m.DB.QueryRowContext(ctx, query, args...).Scan(&compatibility.Id) if err != nil && err != sql.ErrNoRows { return err } return nil } func (m FoundryStateModel) GetWorlds(idState int64) (Worlds, error) { if idState < 1 { return nil, ErrorRecordNotFound } query := ` SELECT id, created_at, text_id, title, description, system, core_version, system_version, playtime, next_session FROM worlds WHERE state_id = $1` ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() rows, err := m.DB.QueryContext(ctx, query, idState) if err != nil { switch { case errors.Is(err, sql.ErrNoRows): return nil, ErrorRecordNotFound default: return nil, err } } worlds := make(Worlds, 0, 1) for rows.Next() { var world World err := rows.Scan( &world.Id, &world.CreatedAt, &world.TextId, &world.Title, &world.Description, &world.System, &world.CoreVersion, &world.SystemVersion, &world.PlayTime, &world.NextSession, ) if err != nil { return nil, err } compatibility, err := m.GetWorldsCompatibility(world.Id) if err != nil { return nil, err } world.Compatibility = *compatibility worlds = append(worlds, world) } if err := rows.Err(); err != nil { return nil, err } return worlds, nil } func (m FoundryStateModel) GetWorldsCompatibility(idWorld int64) (*Compatibility, error) { if idWorld < 1 { return nil, ErrorRecordNotFound } query := ` SELECT id, minimum, verified, maximum FROM worlds_compatibility WHERE world_id = $1` var compatibility Compatibility ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() err := m.DB.QueryRowContext(ctx, query, idWorld).Scan( &compatibility.Id, &compatibility.Minimum, &compatibility.Verified, &compatibility.Maximum, ) if err != nil { switch { case errors.Is(err, sql.ErrNoRows): return nil, ErrorRecordNotFound default: return nil, err } } return &compatibility, nil } func (m FoundryStateModel) DeleteWorlds(idState int64) error { if idState < 1 { return ErrorRecordNotFound } query := ` DELETE FROM worlds WHERE state_id = $1` ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() result, err := m.DB.ExecContext(ctx, query, idState) if err != nil { return err } rowsAffected, err := result.RowsAffected() if err != nil { return err } if rowsAffected == 0 { return ErrorRecordNotFound } return nil } func (m FoundryStateModel) DeleteWorld(idWorld int64) error { if idWorld < 1 { return ErrorRecordNotFound } query := ` DELETE FROM worlds WHERE id = $1` ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() result, err := m.DB.ExecContext(ctx, query, idWorld) if err != nil { return err } rowsAffected, err := result.RowsAffected() if err != nil { return err } if rowsAffected == 0 { return ErrorRecordNotFound } return nil } // func (worlds Worlds) GetSessionTime(worldName string) (*time.Time, error) { // if worldName == "" && len(worlds) != 1 { // return nil, ErrorSetupNotFound // } // if worldName == "" { // return &worlds.GetById(0).NextSession, nil // } else { // for i := range worlds { // if worlds[i].Id == worldName { // return &worlds.GetById(0).NextSession, nil // } // } // } // return nil, ErrorSetupNotFound // } // func (world World) GetSessionTime() *time.Time { // return &world.NextSession // }