| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822 |
- package postgres
- import (
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "time"
- "github.com/jackc/pgx/v5"
- )
- type Place struct {
- ID string
- PublicID string
- Code string
- Name string
- Region *string
- CoverURL *string
- Description *string
- CenterPoint json.RawMessage
- Status string
- CreatedAt time.Time
- UpdatedAt time.Time
- }
- type MapAsset struct {
- ID string
- PublicID string
- PlaceID string
- LegacyMapID *string
- LegacyMapPublicID *string
- Code string
- Name string
- MapType string
- CoverURL *string
- Description *string
- Status string
- CurrentTileReleaseID *string
- CreatedAt time.Time
- UpdatedAt time.Time
- }
- type TileRelease struct {
- ID string
- PublicID string
- MapAssetID string
- LegacyMapVersionID *string
- LegacyMapVersionPub *string
- VersionCode string
- Status string
- TileBaseURL string
- MetaURL string
- PublishedAssetRoot *string
- MetadataJSON json.RawMessage
- PublishedAt *time.Time
- CreatedAt time.Time
- UpdatedAt time.Time
- }
- type CourseSource struct {
- ID string
- PublicID string
- LegacyPlayfieldVersionID *string
- LegacyPlayfieldVersionPub *string
- SourceType string
- FileURL string
- Checksum *string
- ParserVersion *string
- ImportStatus string
- MetadataJSON json.RawMessage
- ImportedAt time.Time
- CreatedAt time.Time
- UpdatedAt time.Time
- }
- type CourseSet struct {
- ID string
- PublicID string
- PlaceID string
- MapAssetID string
- Code string
- Mode string
- Name string
- Description *string
- Status string
- CurrentVariantID *string
- CreatedAt time.Time
- UpdatedAt time.Time
- }
- type CourseVariant struct {
- ID string
- PublicID string
- CourseSetID string
- SourceID *string
- SourcePublicID *string
- Name string
- RouteCode *string
- Mode string
- ControlCount *int
- Difficulty *string
- Status string
- IsDefault bool
- ConfigPatch json.RawMessage
- MetadataJSON json.RawMessage
- CreatedAt time.Time
- UpdatedAt time.Time
- }
- type MapRuntimeBinding struct {
- ID string
- PublicID string
- EventID string
- EventPublicID string
- PlaceID string
- PlacePublicID string
- MapAssetID string
- MapAssetPublicID string
- TileReleaseID string
- TileReleasePublicID string
- CourseSetID string
- CourseSetPublicID string
- CourseVariantID string
- CourseVariantPublicID string
- Status string
- Notes *string
- CreatedAt time.Time
- UpdatedAt time.Time
- }
- type CreatePlaceParams struct {
- PublicID string
- Code string
- Name string
- Region *string
- CoverURL *string
- Description *string
- CenterPoint map[string]any
- Status string
- }
- type CreateMapAssetParams struct {
- PublicID string
- PlaceID string
- LegacyMapID *string
- Code string
- Name string
- MapType string
- CoverURL *string
- Description *string
- Status string
- }
- type CreateTileReleaseParams struct {
- PublicID string
- MapAssetID string
- LegacyMapVersionID *string
- VersionCode string
- Status string
- TileBaseURL string
- MetaURL string
- PublishedAssetRoot *string
- MetadataJSON map[string]any
- PublishedAt *time.Time
- }
- type CreateCourseSourceParams struct {
- PublicID string
- LegacyPlayfieldVersionID *string
- SourceType string
- FileURL string
- Checksum *string
- ParserVersion *string
- ImportStatus string
- MetadataJSON map[string]any
- ImportedAt *time.Time
- }
- type CreateCourseSetParams struct {
- PublicID string
- PlaceID string
- MapAssetID string
- Code string
- Mode string
- Name string
- Description *string
- Status string
- }
- type CreateCourseVariantParams struct {
- PublicID string
- CourseSetID string
- SourceID *string
- Name string
- RouteCode *string
- Mode string
- ControlCount *int
- Difficulty *string
- Status string
- IsDefault bool
- ConfigPatch map[string]any
- MetadataJSON map[string]any
- }
- type CreateMapRuntimeBindingParams struct {
- PublicID string
- EventID string
- PlaceID string
- MapAssetID string
- TileReleaseID string
- CourseSetID string
- CourseVariantID string
- Status string
- Notes *string
- }
- func (s *Store) ListPlaces(ctx context.Context, limit int) ([]Place, error) {
- if limit <= 0 || limit > 200 {
- limit = 50
- }
- rows, err := s.pool.Query(ctx, `
- SELECT id, place_public_id, code, name, region, cover_url, description, center_point_jsonb::text, status, created_at, updated_at
- FROM places
- ORDER BY created_at DESC
- LIMIT $1
- `, limit)
- if err != nil {
- return nil, fmt.Errorf("list places: %w", err)
- }
- defer rows.Close()
- items := []Place{}
- for rows.Next() {
- item, err := scanPlaceFromRows(rows)
- if err != nil {
- return nil, err
- }
- items = append(items, *item)
- }
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("iterate places: %w", err)
- }
- return items, nil
- }
- func (s *Store) GetPlaceByPublicID(ctx context.Context, publicID string) (*Place, error) {
- row := s.pool.QueryRow(ctx, `
- SELECT id, place_public_id, code, name, region, cover_url, description, center_point_jsonb::text, status, created_at, updated_at
- FROM places
- WHERE place_public_id = $1
- LIMIT 1
- `, publicID)
- return scanPlace(row)
- }
- func (s *Store) CreatePlace(ctx context.Context, tx Tx, params CreatePlaceParams) (*Place, error) {
- centerPointJSON, err := marshalJSONMap(params.CenterPoint)
- if err != nil {
- return nil, fmt.Errorf("marshal place center point: %w", err)
- }
- row := tx.QueryRow(ctx, `
- INSERT INTO places (place_public_id, code, name, region, cover_url, description, center_point_jsonb, status)
- VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, $8)
- RETURNING id, place_public_id, code, name, region, cover_url, description, center_point_jsonb::text, status, created_at, updated_at
- `, params.PublicID, params.Code, params.Name, params.Region, params.CoverURL, params.Description, centerPointJSON, params.Status)
- return scanPlace(row)
- }
- func (s *Store) ListMapAssetsByPlaceID(ctx context.Context, placeID string) ([]MapAsset, error) {
- rows, err := s.pool.Query(ctx, `
- SELECT ma.id, ma.map_asset_public_id, ma.place_id, ma.legacy_map_id, lm.map_public_id, ma.code, ma.name, ma.map_type,
- ma.cover_url, ma.description, ma.status, ma.current_tile_release_id, ma.created_at, ma.updated_at
- FROM map_assets ma
- LEFT JOIN maps lm ON lm.id = ma.legacy_map_id
- WHERE ma.place_id = $1
- ORDER BY ma.created_at DESC
- `, placeID)
- if err != nil {
- return nil, fmt.Errorf("list map assets: %w", err)
- }
- defer rows.Close()
- items := []MapAsset{}
- for rows.Next() {
- item, err := scanMapAssetFromRows(rows)
- if err != nil {
- return nil, err
- }
- items = append(items, *item)
- }
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("iterate map assets: %w", err)
- }
- return items, nil
- }
- func (s *Store) GetMapAssetByPublicID(ctx context.Context, publicID string) (*MapAsset, error) {
- row := s.pool.QueryRow(ctx, `
- SELECT ma.id, ma.map_asset_public_id, ma.place_id, ma.legacy_map_id, lm.map_public_id, ma.code, ma.name, ma.map_type,
- ma.cover_url, ma.description, ma.status, ma.current_tile_release_id, ma.created_at, ma.updated_at
- FROM map_assets ma
- LEFT JOIN maps lm ON lm.id = ma.legacy_map_id
- WHERE ma.map_asset_public_id = $1
- LIMIT 1
- `, publicID)
- return scanMapAsset(row)
- }
- func (s *Store) CreateMapAsset(ctx context.Context, tx Tx, params CreateMapAssetParams) (*MapAsset, error) {
- row := tx.QueryRow(ctx, `
- INSERT INTO map_assets (map_asset_public_id, place_id, legacy_map_id, code, name, map_type, cover_url, description, status)
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
- RETURNING id, map_asset_public_id, place_id, legacy_map_id, NULL::text, code, name, map_type, cover_url, description, status, current_tile_release_id, created_at, updated_at
- `, params.PublicID, params.PlaceID, params.LegacyMapID, params.Code, params.Name, params.MapType, params.CoverURL, params.Description, params.Status)
- return scanMapAsset(row)
- }
- func (s *Store) ListTileReleasesByMapAssetID(ctx context.Context, mapAssetID string) ([]TileRelease, error) {
- rows, err := s.pool.Query(ctx, `
- SELECT tr.id, tr.tile_release_public_id, tr.map_asset_id, tr.legacy_map_version_id, mv.version_public_id,
- tr.version_code, tr.status, tr.tile_base_url, tr.meta_url, tr.published_asset_root,
- tr.metadata_jsonb::text, tr.published_at, tr.created_at, tr.updated_at
- FROM tile_releases tr
- LEFT JOIN map_versions mv ON mv.id = tr.legacy_map_version_id
- WHERE tr.map_asset_id = $1
- ORDER BY tr.created_at DESC
- `, mapAssetID)
- if err != nil {
- return nil, fmt.Errorf("list tile releases: %w", err)
- }
- defer rows.Close()
- items := []TileRelease{}
- for rows.Next() {
- item, err := scanTileReleaseFromRows(rows)
- if err != nil {
- return nil, err
- }
- items = append(items, *item)
- }
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("iterate tile releases: %w", err)
- }
- return items, nil
- }
- func (s *Store) GetTileReleaseByPublicID(ctx context.Context, publicID string) (*TileRelease, error) {
- row := s.pool.QueryRow(ctx, `
- SELECT tr.id, tr.tile_release_public_id, tr.map_asset_id, tr.legacy_map_version_id, mv.version_public_id,
- tr.version_code, tr.status, tr.tile_base_url, tr.meta_url, tr.published_asset_root,
- tr.metadata_jsonb::text, tr.published_at, tr.created_at, tr.updated_at
- FROM tile_releases tr
- LEFT JOIN map_versions mv ON mv.id = tr.legacy_map_version_id
- WHERE tr.tile_release_public_id = $1
- LIMIT 1
- `, publicID)
- return scanTileRelease(row)
- }
- func (s *Store) CreateTileRelease(ctx context.Context, tx Tx, params CreateTileReleaseParams) (*TileRelease, error) {
- metadataJSON, err := marshalJSONMap(params.MetadataJSON)
- if err != nil {
- return nil, fmt.Errorf("marshal tile release metadata: %w", err)
- }
- row := tx.QueryRow(ctx, `
- INSERT INTO tile_releases (
- tile_release_public_id, map_asset_id, legacy_map_version_id, version_code, status,
- tile_base_url, meta_url, published_asset_root, metadata_jsonb, published_at
- )
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::jsonb, $10)
- RETURNING id, tile_release_public_id, map_asset_id, legacy_map_version_id, NULL::text, version_code, status,
- tile_base_url, meta_url, published_asset_root, metadata_jsonb::text, published_at, created_at, updated_at
- `, params.PublicID, params.MapAssetID, params.LegacyMapVersionID, params.VersionCode, params.Status, params.TileBaseURL, params.MetaURL, params.PublishedAssetRoot, metadataJSON, params.PublishedAt)
- return scanTileRelease(row)
- }
- func (s *Store) SetMapAssetCurrentTileRelease(ctx context.Context, tx Tx, mapAssetID, tileReleaseID string) error {
- _, err := tx.Exec(ctx, `UPDATE map_assets SET current_tile_release_id = $2 WHERE id = $1`, mapAssetID, tileReleaseID)
- if err != nil {
- return fmt.Errorf("set map asset current tile release: %w", err)
- }
- return nil
- }
- func (s *Store) ListCourseSources(ctx context.Context, limit int) ([]CourseSource, error) {
- if limit <= 0 || limit > 200 {
- limit = 50
- }
- rows, err := s.pool.Query(ctx, `
- SELECT cs.id, cs.course_source_public_id, cs.legacy_playfield_version_id, pv.version_public_id, cs.source_type,
- cs.file_url, cs.checksum, cs.parser_version, cs.import_status, cs.metadata_jsonb::text, cs.imported_at, cs.created_at, cs.updated_at
- FROM course_sources cs
- LEFT JOIN playfield_versions pv ON pv.id = cs.legacy_playfield_version_id
- ORDER BY cs.created_at DESC
- LIMIT $1
- `, limit)
- if err != nil {
- return nil, fmt.Errorf("list course sources: %w", err)
- }
- defer rows.Close()
- items := []CourseSource{}
- for rows.Next() {
- item, err := scanCourseSourceFromRows(rows)
- if err != nil {
- return nil, err
- }
- items = append(items, *item)
- }
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("iterate course sources: %w", err)
- }
- return items, nil
- }
- func (s *Store) GetCourseSourceByPublicID(ctx context.Context, publicID string) (*CourseSource, error) {
- row := s.pool.QueryRow(ctx, `
- SELECT cs.id, cs.course_source_public_id, cs.legacy_playfield_version_id, pv.version_public_id, cs.source_type,
- cs.file_url, cs.checksum, cs.parser_version, cs.import_status, cs.metadata_jsonb::text, cs.imported_at, cs.created_at, cs.updated_at
- FROM course_sources cs
- LEFT JOIN playfield_versions pv ON pv.id = cs.legacy_playfield_version_id
- WHERE cs.course_source_public_id = $1
- LIMIT 1
- `, publicID)
- return scanCourseSource(row)
- }
- func (s *Store) CreateCourseSource(ctx context.Context, tx Tx, params CreateCourseSourceParams) (*CourseSource, error) {
- metadataJSON, err := marshalJSONMap(params.MetadataJSON)
- if err != nil {
- return nil, fmt.Errorf("marshal course source metadata: %w", err)
- }
- importedAt := time.Now()
- if params.ImportedAt != nil {
- importedAt = *params.ImportedAt
- }
- row := tx.QueryRow(ctx, `
- INSERT INTO course_sources (
- course_source_public_id, legacy_playfield_version_id, source_type, file_url, checksum,
- parser_version, import_status, metadata_jsonb, imported_at
- )
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9)
- RETURNING id, course_source_public_id, legacy_playfield_version_id, NULL::text, source_type, file_url,
- checksum, parser_version, import_status, metadata_jsonb::text, imported_at, created_at, updated_at
- `, params.PublicID, params.LegacyPlayfieldVersionID, params.SourceType, params.FileURL, params.Checksum, params.ParserVersion, params.ImportStatus, metadataJSON, importedAt)
- return scanCourseSource(row)
- }
- func (s *Store) ListCourseSets(ctx context.Context, limit int) ([]CourseSet, error) {
- if limit <= 0 || limit > 200 {
- limit = 50
- }
- rows, err := s.pool.Query(ctx, `
- SELECT id, course_set_public_id, place_id, map_asset_id, code, mode, name, description, status, current_variant_id, created_at, updated_at
- FROM course_sets
- ORDER BY created_at DESC
- LIMIT $1
- `, limit)
- if err != nil {
- return nil, fmt.Errorf("list course sets: %w", err)
- }
- defer rows.Close()
- items := []CourseSet{}
- for rows.Next() {
- item, err := scanCourseSetFromRows(rows)
- if err != nil {
- return nil, err
- }
- items = append(items, *item)
- }
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("iterate course sets: %w", err)
- }
- return items, nil
- }
- func (s *Store) ListCourseSetsByMapAssetID(ctx context.Context, mapAssetID string) ([]CourseSet, error) {
- rows, err := s.pool.Query(ctx, `
- SELECT id, course_set_public_id, place_id, map_asset_id, code, mode, name, description, status, current_variant_id, created_at, updated_at
- FROM course_sets
- WHERE map_asset_id = $1
- ORDER BY created_at DESC
- `, mapAssetID)
- if err != nil {
- return nil, fmt.Errorf("list course sets by map asset: %w", err)
- }
- defer rows.Close()
- items := []CourseSet{}
- for rows.Next() {
- item, err := scanCourseSetFromRows(rows)
- if err != nil {
- return nil, err
- }
- items = append(items, *item)
- }
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("iterate course sets by map asset: %w", err)
- }
- return items, nil
- }
- func (s *Store) GetCourseSetByPublicID(ctx context.Context, publicID string) (*CourseSet, error) {
- row := s.pool.QueryRow(ctx, `
- SELECT id, course_set_public_id, place_id, map_asset_id, code, mode, name, description, status, current_variant_id, created_at, updated_at
- FROM course_sets
- WHERE course_set_public_id = $1
- LIMIT 1
- `, publicID)
- return scanCourseSet(row)
- }
- func (s *Store) CreateCourseSet(ctx context.Context, tx Tx, params CreateCourseSetParams) (*CourseSet, error) {
- row := tx.QueryRow(ctx, `
- INSERT INTO course_sets (course_set_public_id, place_id, map_asset_id, code, mode, name, description, status)
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
- RETURNING id, course_set_public_id, place_id, map_asset_id, code, mode, name, description, status, current_variant_id, created_at, updated_at
- `, params.PublicID, params.PlaceID, params.MapAssetID, params.Code, params.Mode, params.Name, params.Description, params.Status)
- return scanCourseSet(row)
- }
- func (s *Store) ListCourseVariantsByCourseSetID(ctx context.Context, courseSetID string) ([]CourseVariant, error) {
- rows, err := s.pool.Query(ctx, `
- SELECT cv.id, cv.course_variant_public_id, cv.course_set_id, cv.source_id, cs.course_source_public_id, cv.name, cv.route_code,
- cv.mode, cv.control_count, cv.difficulty, cv.status, cv.is_default,
- cv.config_patch_jsonb::text, cv.metadata_jsonb::text, cv.created_at, cv.updated_at
- FROM course_variants cv
- LEFT JOIN course_sources cs ON cs.id = cv.source_id
- WHERE cv.course_set_id = $1
- ORDER BY cv.created_at DESC
- `, courseSetID)
- if err != nil {
- return nil, fmt.Errorf("list course variants: %w", err)
- }
- defer rows.Close()
- items := []CourseVariant{}
- for rows.Next() {
- item, err := scanCourseVariantFromRows(rows)
- if err != nil {
- return nil, err
- }
- items = append(items, *item)
- }
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("iterate course variants: %w", err)
- }
- return items, nil
- }
- func (s *Store) GetCourseVariantByPublicID(ctx context.Context, publicID string) (*CourseVariant, error) {
- row := s.pool.QueryRow(ctx, `
- SELECT cv.id, cv.course_variant_public_id, cv.course_set_id, cv.source_id, cs.course_source_public_id, cv.name, cv.route_code,
- cv.mode, cv.control_count, cv.difficulty, cv.status, cv.is_default,
- cv.config_patch_jsonb::text, cv.metadata_jsonb::text, cv.created_at, cv.updated_at
- FROM course_variants cv
- LEFT JOIN course_sources cs ON cs.id = cv.source_id
- WHERE cv.course_variant_public_id = $1
- LIMIT 1
- `, publicID)
- return scanCourseVariant(row)
- }
- func (s *Store) CreateCourseVariant(ctx context.Context, tx Tx, params CreateCourseVariantParams) (*CourseVariant, error) {
- configPatchJSON, err := marshalJSONMap(params.ConfigPatch)
- if err != nil {
- return nil, fmt.Errorf("marshal course variant config patch: %w", err)
- }
- metadataJSON, err := marshalJSONMap(params.MetadataJSON)
- if err != nil {
- return nil, fmt.Errorf("marshal course variant metadata: %w", err)
- }
- row := tx.QueryRow(ctx, `
- INSERT INTO course_variants (
- course_variant_public_id, course_set_id, source_id, name, route_code, mode, control_count,
- difficulty, status, is_default, config_patch_jsonb, metadata_jsonb
- )
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11::jsonb, $12::jsonb)
- RETURNING id, course_variant_public_id, course_set_id, source_id, NULL::text, name, route_code, mode,
- control_count, difficulty, status, is_default, config_patch_jsonb::text, metadata_jsonb::text, created_at, updated_at
- `, params.PublicID, params.CourseSetID, params.SourceID, params.Name, params.RouteCode, params.Mode, params.ControlCount, params.Difficulty, params.Status, params.IsDefault, configPatchJSON, metadataJSON)
- return scanCourseVariant(row)
- }
- func (s *Store) SetCourseSetCurrentVariant(ctx context.Context, tx Tx, courseSetID, variantID string) error {
- _, err := tx.Exec(ctx, `UPDATE course_sets SET current_variant_id = $2 WHERE id = $1`, courseSetID, variantID)
- if err != nil {
- return fmt.Errorf("set course set current variant: %w", err)
- }
- return nil
- }
- func (s *Store) ListMapRuntimeBindings(ctx context.Context, limit int) ([]MapRuntimeBinding, error) {
- if limit <= 0 || limit > 200 {
- limit = 50
- }
- rows, err := s.pool.Query(ctx, `
- SELECT mrb.id, mrb.runtime_binding_public_id, mrb.event_id, e.event_public_id, mrb.place_id, p.place_public_id,
- mrb.map_asset_id, ma.map_asset_public_id, mrb.tile_release_id, tr.tile_release_public_id,
- mrb.course_set_id, cset.course_set_public_id, mrb.course_variant_id, cv.course_variant_public_id,
- mrb.status, mrb.notes, mrb.created_at, mrb.updated_at
- FROM map_runtime_bindings mrb
- JOIN events e ON e.id = mrb.event_id
- JOIN places p ON p.id = mrb.place_id
- JOIN map_assets ma ON ma.id = mrb.map_asset_id
- JOIN tile_releases tr ON tr.id = mrb.tile_release_id
- JOIN course_sets cset ON cset.id = mrb.course_set_id
- JOIN course_variants cv ON cv.id = mrb.course_variant_id
- ORDER BY mrb.created_at DESC
- LIMIT $1
- `, limit)
- if err != nil {
- return nil, fmt.Errorf("list runtime bindings: %w", err)
- }
- defer rows.Close()
- items := []MapRuntimeBinding{}
- for rows.Next() {
- item, err := scanMapRuntimeBindingFromRows(rows)
- if err != nil {
- return nil, err
- }
- items = append(items, *item)
- }
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("iterate runtime bindings: %w", err)
- }
- return items, nil
- }
- func (s *Store) GetMapRuntimeBindingByPublicID(ctx context.Context, publicID string) (*MapRuntimeBinding, error) {
- row := s.pool.QueryRow(ctx, `
- SELECT mrb.id, mrb.runtime_binding_public_id, mrb.event_id, e.event_public_id, mrb.place_id, p.place_public_id,
- mrb.map_asset_id, ma.map_asset_public_id, mrb.tile_release_id, tr.tile_release_public_id,
- mrb.course_set_id, cset.course_set_public_id, mrb.course_variant_id, cv.course_variant_public_id,
- mrb.status, mrb.notes, mrb.created_at, mrb.updated_at
- FROM map_runtime_bindings mrb
- JOIN events e ON e.id = mrb.event_id
- JOIN places p ON p.id = mrb.place_id
- JOIN map_assets ma ON ma.id = mrb.map_asset_id
- JOIN tile_releases tr ON tr.id = mrb.tile_release_id
- JOIN course_sets cset ON cset.id = mrb.course_set_id
- JOIN course_variants cv ON cv.id = mrb.course_variant_id
- WHERE mrb.runtime_binding_public_id = $1
- LIMIT 1
- `, publicID)
- return scanMapRuntimeBinding(row)
- }
- func (s *Store) CreateMapRuntimeBinding(ctx context.Context, tx Tx, params CreateMapRuntimeBindingParams) (*MapRuntimeBinding, error) {
- row := tx.QueryRow(ctx, `
- INSERT INTO map_runtime_bindings (
- runtime_binding_public_id, event_id, place_id, map_asset_id, tile_release_id, course_set_id, course_variant_id, status, notes
- )
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
- RETURNING id, runtime_binding_public_id, event_id, ''::text, place_id, ''::text, map_asset_id, ''::text,
- tile_release_id, ''::text, course_set_id, ''::text, course_variant_id, ''::text,
- status, notes, created_at, updated_at
- `, params.PublicID, params.EventID, params.PlaceID, params.MapAssetID, params.TileReleaseID, params.CourseSetID, params.CourseVariantID, params.Status, params.Notes)
- return scanMapRuntimeBinding(row)
- }
- func scanPlace(row pgx.Row) (*Place, error) {
- var item Place
- var centerPoint string
- err := row.Scan(&item.ID, &item.PublicID, &item.Code, &item.Name, &item.Region, &item.CoverURL, &item.Description, ¢erPoint, &item.Status, &item.CreatedAt, &item.UpdatedAt)
- if errors.Is(err, pgx.ErrNoRows) {
- return nil, nil
- }
- if err != nil {
- return nil, fmt.Errorf("scan place: %w", err)
- }
- item.CenterPoint = json.RawMessage(centerPoint)
- return &item, nil
- }
- func scanPlaceFromRows(rows pgx.Rows) (*Place, error) {
- var item Place
- var centerPoint string
- err := rows.Scan(&item.ID, &item.PublicID, &item.Code, &item.Name, &item.Region, &item.CoverURL, &item.Description, ¢erPoint, &item.Status, &item.CreatedAt, &item.UpdatedAt)
- if err != nil {
- return nil, fmt.Errorf("scan place row: %w", err)
- }
- item.CenterPoint = json.RawMessage(centerPoint)
- return &item, nil
- }
- func scanMapAsset(row pgx.Row) (*MapAsset, error) {
- var item MapAsset
- err := row.Scan(&item.ID, &item.PublicID, &item.PlaceID, &item.LegacyMapID, &item.LegacyMapPublicID, &item.Code, &item.Name, &item.MapType, &item.CoverURL, &item.Description, &item.Status, &item.CurrentTileReleaseID, &item.CreatedAt, &item.UpdatedAt)
- if errors.Is(err, pgx.ErrNoRows) {
- return nil, nil
- }
- if err != nil {
- return nil, fmt.Errorf("scan map asset: %w", err)
- }
- return &item, nil
- }
- func scanMapAssetFromRows(rows pgx.Rows) (*MapAsset, error) {
- var item MapAsset
- err := rows.Scan(&item.ID, &item.PublicID, &item.PlaceID, &item.LegacyMapID, &item.LegacyMapPublicID, &item.Code, &item.Name, &item.MapType, &item.CoverURL, &item.Description, &item.Status, &item.CurrentTileReleaseID, &item.CreatedAt, &item.UpdatedAt)
- if err != nil {
- return nil, fmt.Errorf("scan map asset row: %w", err)
- }
- return &item, nil
- }
- func scanTileRelease(row pgx.Row) (*TileRelease, error) {
- var item TileRelease
- var metadataJSON string
- err := row.Scan(&item.ID, &item.PublicID, &item.MapAssetID, &item.LegacyMapVersionID, &item.LegacyMapVersionPub, &item.VersionCode, &item.Status, &item.TileBaseURL, &item.MetaURL, &item.PublishedAssetRoot, &metadataJSON, &item.PublishedAt, &item.CreatedAt, &item.UpdatedAt)
- if errors.Is(err, pgx.ErrNoRows) {
- return nil, nil
- }
- if err != nil {
- return nil, fmt.Errorf("scan tile release: %w", err)
- }
- item.MetadataJSON = json.RawMessage(metadataJSON)
- return &item, nil
- }
- func scanTileReleaseFromRows(rows pgx.Rows) (*TileRelease, error) {
- var item TileRelease
- var metadataJSON string
- err := rows.Scan(&item.ID, &item.PublicID, &item.MapAssetID, &item.LegacyMapVersionID, &item.LegacyMapVersionPub, &item.VersionCode, &item.Status, &item.TileBaseURL, &item.MetaURL, &item.PublishedAssetRoot, &metadataJSON, &item.PublishedAt, &item.CreatedAt, &item.UpdatedAt)
- if err != nil {
- return nil, fmt.Errorf("scan tile release row: %w", err)
- }
- item.MetadataJSON = json.RawMessage(metadataJSON)
- return &item, nil
- }
- func scanCourseSource(row pgx.Row) (*CourseSource, error) {
- var item CourseSource
- var metadataJSON string
- err := row.Scan(&item.ID, &item.PublicID, &item.LegacyPlayfieldVersionID, &item.LegacyPlayfieldVersionPub, &item.SourceType, &item.FileURL, &item.Checksum, &item.ParserVersion, &item.ImportStatus, &metadataJSON, &item.ImportedAt, &item.CreatedAt, &item.UpdatedAt)
- if errors.Is(err, pgx.ErrNoRows) {
- return nil, nil
- }
- if err != nil {
- return nil, fmt.Errorf("scan course source: %w", err)
- }
- item.MetadataJSON = json.RawMessage(metadataJSON)
- return &item, nil
- }
- func scanCourseSourceFromRows(rows pgx.Rows) (*CourseSource, error) {
- var item CourseSource
- var metadataJSON string
- err := rows.Scan(&item.ID, &item.PublicID, &item.LegacyPlayfieldVersionID, &item.LegacyPlayfieldVersionPub, &item.SourceType, &item.FileURL, &item.Checksum, &item.ParserVersion, &item.ImportStatus, &metadataJSON, &item.ImportedAt, &item.CreatedAt, &item.UpdatedAt)
- if err != nil {
- return nil, fmt.Errorf("scan course source row: %w", err)
- }
- item.MetadataJSON = json.RawMessage(metadataJSON)
- return &item, nil
- }
- func scanCourseSet(row pgx.Row) (*CourseSet, error) {
- var item CourseSet
- err := row.Scan(&item.ID, &item.PublicID, &item.PlaceID, &item.MapAssetID, &item.Code, &item.Mode, &item.Name, &item.Description, &item.Status, &item.CurrentVariantID, &item.CreatedAt, &item.UpdatedAt)
- if errors.Is(err, pgx.ErrNoRows) {
- return nil, nil
- }
- if err != nil {
- return nil, fmt.Errorf("scan course set: %w", err)
- }
- return &item, nil
- }
- func scanCourseSetFromRows(rows pgx.Rows) (*CourseSet, error) {
- var item CourseSet
- err := rows.Scan(&item.ID, &item.PublicID, &item.PlaceID, &item.MapAssetID, &item.Code, &item.Mode, &item.Name, &item.Description, &item.Status, &item.CurrentVariantID, &item.CreatedAt, &item.UpdatedAt)
- if err != nil {
- return nil, fmt.Errorf("scan course set row: %w", err)
- }
- return &item, nil
- }
- func scanCourseVariant(row pgx.Row) (*CourseVariant, error) {
- var item CourseVariant
- var configPatch string
- var metadataJSON string
- err := row.Scan(&item.ID, &item.PublicID, &item.CourseSetID, &item.SourceID, &item.SourcePublicID, &item.Name, &item.RouteCode, &item.Mode, &item.ControlCount, &item.Difficulty, &item.Status, &item.IsDefault, &configPatch, &metadataJSON, &item.CreatedAt, &item.UpdatedAt)
- if errors.Is(err, pgx.ErrNoRows) {
- return nil, nil
- }
- if err != nil {
- return nil, fmt.Errorf("scan course variant: %w", err)
- }
- item.ConfigPatch = json.RawMessage(configPatch)
- item.MetadataJSON = json.RawMessage(metadataJSON)
- return &item, nil
- }
- func scanCourseVariantFromRows(rows pgx.Rows) (*CourseVariant, error) {
- var item CourseVariant
- var configPatch string
- var metadataJSON string
- err := rows.Scan(&item.ID, &item.PublicID, &item.CourseSetID, &item.SourceID, &item.SourcePublicID, &item.Name, &item.RouteCode, &item.Mode, &item.ControlCount, &item.Difficulty, &item.Status, &item.IsDefault, &configPatch, &metadataJSON, &item.CreatedAt, &item.UpdatedAt)
- if err != nil {
- return nil, fmt.Errorf("scan course variant row: %w", err)
- }
- item.ConfigPatch = json.RawMessage(configPatch)
- item.MetadataJSON = json.RawMessage(metadataJSON)
- return &item, nil
- }
- func scanMapRuntimeBinding(row pgx.Row) (*MapRuntimeBinding, error) {
- var item MapRuntimeBinding
- err := row.Scan(&item.ID, &item.PublicID, &item.EventID, &item.EventPublicID, &item.PlaceID, &item.PlacePublicID, &item.MapAssetID, &item.MapAssetPublicID, &item.TileReleaseID, &item.TileReleasePublicID, &item.CourseSetID, &item.CourseSetPublicID, &item.CourseVariantID, &item.CourseVariantPublicID, &item.Status, &item.Notes, &item.CreatedAt, &item.UpdatedAt)
- if errors.Is(err, pgx.ErrNoRows) {
- return nil, nil
- }
- if err != nil {
- return nil, fmt.Errorf("scan runtime binding: %w", err)
- }
- return &item, nil
- }
- func scanMapRuntimeBindingFromRows(rows pgx.Rows) (*MapRuntimeBinding, error) {
- var item MapRuntimeBinding
- err := rows.Scan(&item.ID, &item.PublicID, &item.EventID, &item.EventPublicID, &item.PlaceID, &item.PlacePublicID, &item.MapAssetID, &item.MapAssetPublicID, &item.TileReleaseID, &item.TileReleasePublicID, &item.CourseSetID, &item.CourseSetPublicID, &item.CourseVariantID, &item.CourseVariantPublicID, &item.Status, &item.Notes, &item.CreatedAt, &item.UpdatedAt)
- if err != nil {
- return nil, fmt.Errorf("scan runtime binding row: %w", err)
- }
- return &item, nil
- }
|