| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560 |
- package postgres
- import (
- "context"
- "errors"
- "fmt"
- "github.com/jackc/pgx/v5"
- )
- type EventPresentation struct {
- ID string
- PublicID string
- EventID string
- EventPublicID string
- Code string
- Name string
- PresentationType string
- Status string
- IsDefault bool
- SchemaJSON string
- CreatedAt string
- UpdatedAt string
- }
- type ContentBundle struct {
- ID string
- PublicID string
- EventID string
- EventPublicID string
- Code string
- Name string
- Status string
- IsDefault bool
- EntryURL *string
- AssetRootURL *string
- MetadataJSON string
- CreatedAt string
- UpdatedAt string
- }
- type CreateEventPresentationParams struct {
- PublicID string
- EventID string
- Code string
- Name string
- PresentationType string
- Status string
- IsDefault bool
- SchemaJSON string
- }
- type CreateContentBundleParams struct {
- PublicID string
- EventID string
- Code string
- Name string
- Status string
- IsDefault bool
- EntryURL *string
- AssetRootURL *string
- MetadataJSON string
- }
- type EventDefaultBindings struct {
- EventID string
- EventPublicID string
- PresentationID *string
- PresentationPublicID *string
- PresentationName *string
- PresentationType *string
- ContentBundleID *string
- ContentBundlePublicID *string
- ContentBundleName *string
- ContentEntryURL *string
- ContentAssetRootURL *string
- RuntimeBindingID *string
- RuntimeBindingPublicID *string
- PlacePublicID *string
- PlaceName *string
- MapAssetPublicID *string
- MapAssetName *string
- TileReleasePublicID *string
- CourseSetPublicID *string
- CourseVariantPublicID *string
- CourseVariantName *string
- RuntimeRouteCode *string
- }
- type SetEventDefaultBindingsParams struct {
- EventID string
- PresentationID *string
- ContentBundleID *string
- RuntimeBindingID *string
- UpdatePresentation bool
- UpdateContent bool
- UpdateRuntime bool
- }
- func (s *Store) ListEventPresentationsByEventID(ctx context.Context, eventID string, limit int) ([]EventPresentation, error) {
- if limit <= 0 || limit > 200 {
- limit = 50
- }
- rows, err := s.pool.Query(ctx, `
- SELECT
- ep.id,
- ep.presentation_public_id,
- ep.event_id,
- e.event_public_id,
- ep.code,
- ep.name,
- ep.presentation_type,
- ep.status,
- ep.is_default,
- ep.schema_jsonb::text,
- ep.created_at::text,
- ep.updated_at::text
- FROM event_presentations ep
- JOIN events e ON e.id = ep.event_id
- WHERE ep.event_id = $1
- ORDER BY ep.is_default DESC, ep.created_at DESC
- LIMIT $2
- `, eventID, limit)
- if err != nil {
- return nil, fmt.Errorf("list event presentations: %w", err)
- }
- defer rows.Close()
- items := []EventPresentation{}
- for rows.Next() {
- item, err := scanEventPresentationFromRows(rows)
- if err != nil {
- return nil, err
- }
- items = append(items, *item)
- }
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("iterate event presentations: %w", err)
- }
- return items, nil
- }
- func (s *Store) GetEventPresentationByPublicID(ctx context.Context, publicID string) (*EventPresentation, error) {
- row := s.pool.QueryRow(ctx, `
- SELECT
- ep.id,
- ep.presentation_public_id,
- ep.event_id,
- e.event_public_id,
- ep.code,
- ep.name,
- ep.presentation_type,
- ep.status,
- ep.is_default,
- ep.schema_jsonb::text,
- ep.created_at::text,
- ep.updated_at::text
- FROM event_presentations ep
- JOIN events e ON e.id = ep.event_id
- WHERE ep.presentation_public_id = $1
- LIMIT 1
- `, publicID)
- return scanEventPresentation(row)
- }
- func (s *Store) GetDefaultEventPresentationByEventID(ctx context.Context, eventID string) (*EventPresentation, error) {
- row := s.pool.QueryRow(ctx, `
- SELECT
- ep.id,
- ep.presentation_public_id,
- ep.event_id,
- e.event_public_id,
- ep.code,
- ep.name,
- ep.presentation_type,
- ep.status,
- ep.is_default,
- ep.schema_jsonb::text,
- ep.created_at::text,
- ep.updated_at::text
- FROM event_presentations ep
- JOIN events e ON e.id = ep.event_id
- WHERE ep.event_id = $1
- AND ep.status = 'active'
- ORDER BY ep.is_default DESC, ep.updated_at DESC, ep.created_at DESC
- LIMIT 1
- `, eventID)
- return scanEventPresentation(row)
- }
- func (s *Store) CreateEventPresentation(ctx context.Context, tx Tx, params CreateEventPresentationParams) (*EventPresentation, error) {
- row := tx.QueryRow(ctx, `
- INSERT INTO event_presentations (
- presentation_public_id,
- event_id,
- code,
- name,
- presentation_type,
- status,
- is_default,
- schema_jsonb
- )
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb)
- RETURNING
- id,
- presentation_public_id,
- event_id,
- code,
- name,
- presentation_type,
- status,
- is_default,
- schema_jsonb::text,
- created_at::text,
- updated_at::text
- `, params.PublicID, params.EventID, params.Code, params.Name, params.PresentationType, params.Status, params.IsDefault, params.SchemaJSON)
- var item EventPresentation
- if err := row.Scan(
- &item.ID,
- &item.PublicID,
- &item.EventID,
- &item.Code,
- &item.Name,
- &item.PresentationType,
- &item.Status,
- &item.IsDefault,
- &item.SchemaJSON,
- &item.CreatedAt,
- &item.UpdatedAt,
- ); err != nil {
- return nil, fmt.Errorf("create event presentation: %w", err)
- }
- return &item, nil
- }
- func (s *Store) GetEventDefaultBindingsByEventID(ctx context.Context, eventID string) (*EventDefaultBindings, error) {
- row := s.pool.QueryRow(ctx, `
- SELECT
- e.id,
- e.event_public_id,
- e.current_presentation_id,
- ep.presentation_public_id,
- ep.name,
- ep.presentation_type,
- e.current_content_bundle_id,
- cb.content_bundle_public_id,
- cb.name,
- cb.entry_url,
- cb.asset_root_url,
- e.current_runtime_binding_id,
- mrb.runtime_binding_public_id,
- p.place_public_id,
- p.name,
- ma.map_asset_public_id,
- ma.name,
- tr.tile_release_public_id,
- cset.course_set_public_id,
- cv.course_variant_public_id,
- cv.name,
- cv.route_code
- FROM events e
- LEFT JOIN event_presentations ep ON ep.id = e.current_presentation_id
- LEFT JOIN content_bundles cb ON cb.id = e.current_content_bundle_id
- LEFT JOIN map_runtime_bindings mrb ON mrb.id = e.current_runtime_binding_id
- LEFT JOIN places p ON p.id = mrb.place_id
- LEFT JOIN map_assets ma ON ma.id = mrb.map_asset_id
- LEFT JOIN tile_releases tr ON tr.id = mrb.tile_release_id
- LEFT JOIN course_sets cset ON cset.id = mrb.course_set_id
- LEFT JOIN course_variants cv ON cv.id = mrb.course_variant_id
- WHERE e.id = $1
- LIMIT 1
- `, eventID)
- return scanEventDefaultBindings(row)
- }
- func (s *Store) SetEventDefaultBindings(ctx context.Context, tx Tx, params SetEventDefaultBindingsParams) error {
- if _, err := tx.Exec(ctx, `
- UPDATE events
- SET current_presentation_id = CASE WHEN $5 THEN $2 ELSE current_presentation_id END,
- current_content_bundle_id = CASE WHEN $6 THEN $3 ELSE current_content_bundle_id END,
- current_runtime_binding_id = CASE WHEN $7 THEN $4 ELSE current_runtime_binding_id END
- WHERE id = $1
- `, params.EventID, params.PresentationID, params.ContentBundleID, params.RuntimeBindingID, params.UpdatePresentation, params.UpdateContent, params.UpdateRuntime); err != nil {
- return fmt.Errorf("set event default bindings: %w", err)
- }
- return nil
- }
- func (s *Store) ListContentBundlesByEventID(ctx context.Context, eventID string, limit int) ([]ContentBundle, error) {
- if limit <= 0 || limit > 200 {
- limit = 50
- }
- rows, err := s.pool.Query(ctx, `
- SELECT
- cb.id,
- cb.content_bundle_public_id,
- cb.event_id,
- e.event_public_id,
- cb.code,
- cb.name,
- cb.status,
- cb.is_default,
- cb.entry_url,
- cb.asset_root_url,
- cb.metadata_jsonb::text,
- cb.created_at::text,
- cb.updated_at::text
- FROM content_bundles cb
- JOIN events e ON e.id = cb.event_id
- WHERE cb.event_id = $1
- ORDER BY cb.is_default DESC, cb.created_at DESC
- LIMIT $2
- `, eventID, limit)
- if err != nil {
- return nil, fmt.Errorf("list content bundles: %w", err)
- }
- defer rows.Close()
- items := []ContentBundle{}
- for rows.Next() {
- item, err := scanContentBundleFromRows(rows)
- if err != nil {
- return nil, err
- }
- items = append(items, *item)
- }
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("iterate content bundles: %w", err)
- }
- return items, nil
- }
- func (s *Store) GetContentBundleByPublicID(ctx context.Context, publicID string) (*ContentBundle, error) {
- row := s.pool.QueryRow(ctx, `
- SELECT
- cb.id,
- cb.content_bundle_public_id,
- cb.event_id,
- e.event_public_id,
- cb.code,
- cb.name,
- cb.status,
- cb.is_default,
- cb.entry_url,
- cb.asset_root_url,
- cb.metadata_jsonb::text,
- cb.created_at::text,
- cb.updated_at::text
- FROM content_bundles cb
- JOIN events e ON e.id = cb.event_id
- WHERE cb.content_bundle_public_id = $1
- LIMIT 1
- `, publicID)
- return scanContentBundle(row)
- }
- func (s *Store) GetDefaultContentBundleByEventID(ctx context.Context, eventID string) (*ContentBundle, error) {
- row := s.pool.QueryRow(ctx, `
- SELECT
- cb.id,
- cb.content_bundle_public_id,
- cb.event_id,
- e.event_public_id,
- cb.code,
- cb.name,
- cb.status,
- cb.is_default,
- cb.entry_url,
- cb.asset_root_url,
- cb.metadata_jsonb::text,
- cb.created_at::text,
- cb.updated_at::text
- FROM content_bundles cb
- JOIN events e ON e.id = cb.event_id
- WHERE cb.event_id = $1
- AND cb.status = 'active'
- ORDER BY cb.is_default DESC, cb.updated_at DESC, cb.created_at DESC
- LIMIT 1
- `, eventID)
- return scanContentBundle(row)
- }
- func (s *Store) CreateContentBundle(ctx context.Context, tx Tx, params CreateContentBundleParams) (*ContentBundle, error) {
- row := tx.QueryRow(ctx, `
- INSERT INTO content_bundles (
- content_bundle_public_id,
- event_id,
- code,
- name,
- status,
- is_default,
- entry_url,
- asset_root_url,
- metadata_jsonb
- )
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::jsonb)
- RETURNING
- id,
- content_bundle_public_id,
- event_id,
- code,
- name,
- status,
- is_default,
- entry_url,
- asset_root_url,
- metadata_jsonb::text,
- created_at::text,
- updated_at::text
- `, params.PublicID, params.EventID, params.Code, params.Name, params.Status, params.IsDefault, params.EntryURL, params.AssetRootURL, params.MetadataJSON)
- var item ContentBundle
- if err := row.Scan(
- &item.ID,
- &item.PublicID,
- &item.EventID,
- &item.Code,
- &item.Name,
- &item.Status,
- &item.IsDefault,
- &item.EntryURL,
- &item.AssetRootURL,
- &item.MetadataJSON,
- &item.CreatedAt,
- &item.UpdatedAt,
- ); err != nil {
- return nil, fmt.Errorf("create content bundle: %w", err)
- }
- return &item, nil
- }
- func scanEventPresentation(row pgx.Row) (*EventPresentation, error) {
- var item EventPresentation
- err := row.Scan(
- &item.ID,
- &item.PublicID,
- &item.EventID,
- &item.EventPublicID,
- &item.Code,
- &item.Name,
- &item.PresentationType,
- &item.Status,
- &item.IsDefault,
- &item.SchemaJSON,
- &item.CreatedAt,
- &item.UpdatedAt,
- )
- if errors.Is(err, pgx.ErrNoRows) {
- return nil, nil
- }
- if err != nil {
- return nil, fmt.Errorf("scan event presentation: %w", err)
- }
- return &item, nil
- }
- func scanEventPresentationFromRows(rows pgx.Rows) (*EventPresentation, error) {
- var item EventPresentation
- if err := rows.Scan(
- &item.ID,
- &item.PublicID,
- &item.EventID,
- &item.EventPublicID,
- &item.Code,
- &item.Name,
- &item.PresentationType,
- &item.Status,
- &item.IsDefault,
- &item.SchemaJSON,
- &item.CreatedAt,
- &item.UpdatedAt,
- ); err != nil {
- return nil, fmt.Errorf("scan event presentation row: %w", err)
- }
- return &item, nil
- }
- func scanContentBundle(row pgx.Row) (*ContentBundle, error) {
- var item ContentBundle
- err := row.Scan(
- &item.ID,
- &item.PublicID,
- &item.EventID,
- &item.EventPublicID,
- &item.Code,
- &item.Name,
- &item.Status,
- &item.IsDefault,
- &item.EntryURL,
- &item.AssetRootURL,
- &item.MetadataJSON,
- &item.CreatedAt,
- &item.UpdatedAt,
- )
- if errors.Is(err, pgx.ErrNoRows) {
- return nil, nil
- }
- if err != nil {
- return nil, fmt.Errorf("scan content bundle: %w", err)
- }
- return &item, nil
- }
- func scanContentBundleFromRows(rows pgx.Rows) (*ContentBundle, error) {
- var item ContentBundle
- if err := rows.Scan(
- &item.ID,
- &item.PublicID,
- &item.EventID,
- &item.EventPublicID,
- &item.Code,
- &item.Name,
- &item.Status,
- &item.IsDefault,
- &item.EntryURL,
- &item.AssetRootURL,
- &item.MetadataJSON,
- &item.CreatedAt,
- &item.UpdatedAt,
- ); err != nil {
- return nil, fmt.Errorf("scan content bundle row: %w", err)
- }
- return &item, nil
- }
- func scanEventDefaultBindings(row pgx.Row) (*EventDefaultBindings, error) {
- var item EventDefaultBindings
- err := row.Scan(
- &item.EventID,
- &item.EventPublicID,
- &item.PresentationID,
- &item.PresentationPublicID,
- &item.PresentationName,
- &item.PresentationType,
- &item.ContentBundleID,
- &item.ContentBundlePublicID,
- &item.ContentBundleName,
- &item.ContentEntryURL,
- &item.ContentAssetRootURL,
- &item.RuntimeBindingID,
- &item.RuntimeBindingPublicID,
- &item.PlacePublicID,
- &item.PlaceName,
- &item.MapAssetPublicID,
- &item.MapAssetName,
- &item.TileReleasePublicID,
- &item.CourseSetPublicID,
- &item.CourseVariantPublicID,
- &item.CourseVariantName,
- &item.RuntimeRouteCode,
- )
- if errors.Is(err, pgx.ErrNoRows) {
- return nil, nil
- }
- if err != nil {
- return nil, fmt.Errorf("scan event default bindings: %w", err)
- }
- return &item, nil
- }
|