379 lines
10 KiB
Go
379 lines
10 KiB
Go
package postgres
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
type Tenant struct {
|
|
ID string
|
|
TenantCode string
|
|
Name string
|
|
Status string
|
|
}
|
|
|
|
type AdminEventRecord struct {
|
|
ID string
|
|
PublicID string
|
|
TenantID *string
|
|
TenantCode *string
|
|
TenantName *string
|
|
Slug string
|
|
DisplayName string
|
|
Summary *string
|
|
Status string
|
|
CurrentReleaseID *string
|
|
CurrentReleasePubID *string
|
|
ConfigLabel *string
|
|
ManifestURL *string
|
|
ManifestChecksum *string
|
|
RouteCode *string
|
|
PresentationID *string
|
|
PresentationName *string
|
|
PresentationType *string
|
|
ContentBundleID *string
|
|
ContentBundleName *string
|
|
ContentEntryURL *string
|
|
ContentAssetRootURL *string
|
|
CurrentPresentationID *string
|
|
CurrentPresentationName *string
|
|
CurrentPresentationType *string
|
|
CurrentContentBundleID *string
|
|
CurrentContentBundleName *string
|
|
CurrentContentEntryURL *string
|
|
CurrentContentAssetRootURL *string
|
|
CurrentRuntimeBindingID *string
|
|
CurrentPlaceID *string
|
|
CurrentMapAssetID *string
|
|
CurrentTileReleaseID *string
|
|
CurrentCourseSetID *string
|
|
CurrentCourseVariantID *string
|
|
CurrentCourseVariantName *string
|
|
CurrentRuntimeRouteCode *string
|
|
}
|
|
|
|
type CreateAdminEventParams struct {
|
|
PublicID string
|
|
TenantID *string
|
|
Slug string
|
|
DisplayName string
|
|
Summary *string
|
|
Status string
|
|
}
|
|
|
|
type UpdateAdminEventParams struct {
|
|
EventID string
|
|
TenantID *string
|
|
Slug string
|
|
DisplayName string
|
|
Summary *string
|
|
Status string
|
|
ClearTenant bool
|
|
}
|
|
|
|
func (s *Store) GetTenantByCode(ctx context.Context, tenantCode string) (*Tenant, error) {
|
|
row := s.pool.QueryRow(ctx, `
|
|
SELECT id, tenant_code, name, status
|
|
FROM tenants
|
|
WHERE tenant_code = $1
|
|
LIMIT 1
|
|
`, tenantCode)
|
|
var item Tenant
|
|
err := row.Scan(&item.ID, &item.TenantCode, &item.Name, &item.Status)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, nil
|
|
}
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get tenant by code: %w", err)
|
|
}
|
|
return &item, nil
|
|
}
|
|
|
|
func (s *Store) ListAdminEvents(ctx context.Context, limit int) ([]AdminEventRecord, error) {
|
|
if limit <= 0 || limit > 200 {
|
|
limit = 50
|
|
}
|
|
rows, err := s.pool.Query(ctx, `
|
|
SELECT
|
|
e.id,
|
|
e.event_public_id,
|
|
e.tenant_id,
|
|
t.tenant_code,
|
|
t.name,
|
|
e.slug,
|
|
e.display_name,
|
|
e.summary,
|
|
e.status,
|
|
e.current_release_id,
|
|
er.release_public_id,
|
|
er.config_label,
|
|
er.manifest_url,
|
|
er.manifest_checksum_sha256,
|
|
er.route_code,
|
|
ep.presentation_public_id,
|
|
ep.name,
|
|
ep.presentation_type,
|
|
cb.content_bundle_public_id,
|
|
cb.name,
|
|
cb.entry_url,
|
|
cb.asset_root_url,
|
|
epc.presentation_public_id,
|
|
epc.name,
|
|
epc.presentation_type,
|
|
cbc.content_bundle_public_id,
|
|
cbc.name,
|
|
cbc.entry_url,
|
|
cbc.asset_root_url,
|
|
mrb.runtime_binding_public_id,
|
|
p.place_public_id,
|
|
ma.map_asset_public_id,
|
|
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 tenants t ON t.id = e.tenant_id
|
|
LEFT JOIN event_releases er ON er.id = e.current_release_id
|
|
LEFT JOIN event_presentations ep ON ep.id = er.presentation_id
|
|
LEFT JOIN content_bundles cb ON cb.id = er.content_bundle_id
|
|
LEFT JOIN event_presentations epc ON epc.id = e.current_presentation_id
|
|
LEFT JOIN content_bundles cbc ON cbc.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
|
|
ORDER BY e.created_at DESC
|
|
LIMIT $1
|
|
`, limit)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list admin events: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
items := []AdminEventRecord{}
|
|
for rows.Next() {
|
|
item, err := scanAdminEventFromRows(rows)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, *item)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, fmt.Errorf("iterate admin events: %w", err)
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
func (s *Store) GetAdminEventByPublicID(ctx context.Context, eventPublicID string) (*AdminEventRecord, error) {
|
|
row := s.pool.QueryRow(ctx, `
|
|
SELECT
|
|
e.id,
|
|
e.event_public_id,
|
|
e.tenant_id,
|
|
t.tenant_code,
|
|
t.name,
|
|
e.slug,
|
|
e.display_name,
|
|
e.summary,
|
|
e.status,
|
|
e.current_release_id,
|
|
er.release_public_id,
|
|
er.config_label,
|
|
er.manifest_url,
|
|
er.manifest_checksum_sha256,
|
|
er.route_code,
|
|
ep.presentation_public_id,
|
|
ep.name,
|
|
ep.presentation_type,
|
|
cb.content_bundle_public_id,
|
|
cb.name,
|
|
cb.entry_url,
|
|
cb.asset_root_url,
|
|
epc.presentation_public_id,
|
|
epc.name,
|
|
epc.presentation_type,
|
|
cbc.content_bundle_public_id,
|
|
cbc.name,
|
|
cbc.entry_url,
|
|
cbc.asset_root_url,
|
|
mrb.runtime_binding_public_id,
|
|
p.place_public_id,
|
|
ma.map_asset_public_id,
|
|
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 tenants t ON t.id = e.tenant_id
|
|
LEFT JOIN event_releases er ON er.id = e.current_release_id
|
|
LEFT JOIN event_presentations ep ON ep.id = er.presentation_id
|
|
LEFT JOIN content_bundles cb ON cb.id = er.content_bundle_id
|
|
LEFT JOIN event_presentations epc ON epc.id = e.current_presentation_id
|
|
LEFT JOIN content_bundles cbc ON cbc.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.event_public_id = $1
|
|
LIMIT 1
|
|
`, eventPublicID)
|
|
return scanAdminEvent(row)
|
|
}
|
|
|
|
func (s *Store) CreateAdminEvent(ctx context.Context, tx Tx, params CreateAdminEventParams) (*AdminEventRecord, error) {
|
|
row := tx.QueryRow(ctx, `
|
|
INSERT INTO events (tenant_id, event_public_id, slug, display_name, summary, status)
|
|
VALUES ($1, $2, $3, $4, $5, $6)
|
|
RETURNING id, event_public_id, tenant_id, slug, display_name, summary, status, current_release_id
|
|
`, params.TenantID, params.PublicID, params.Slug, params.DisplayName, params.Summary, params.Status)
|
|
|
|
var item AdminEventRecord
|
|
if err := row.Scan(
|
|
&item.ID,
|
|
&item.PublicID,
|
|
&item.TenantID,
|
|
&item.Slug,
|
|
&item.DisplayName,
|
|
&item.Summary,
|
|
&item.Status,
|
|
&item.CurrentReleaseID,
|
|
); err != nil {
|
|
return nil, fmt.Errorf("create admin event: %w", err)
|
|
}
|
|
return &item, nil
|
|
}
|
|
|
|
func (s *Store) UpdateAdminEvent(ctx context.Context, tx Tx, params UpdateAdminEventParams) (*AdminEventRecord, error) {
|
|
row := tx.QueryRow(ctx, `
|
|
UPDATE events
|
|
SET tenant_id = CASE WHEN $7 THEN NULL ELSE $2 END,
|
|
slug = $3,
|
|
display_name = $4,
|
|
summary = $5,
|
|
status = $6
|
|
WHERE id = $1
|
|
RETURNING id, event_public_id, tenant_id, slug, display_name, summary, status, current_release_id
|
|
`, params.EventID, params.TenantID, params.Slug, params.DisplayName, params.Summary, params.Status, params.ClearTenant)
|
|
|
|
var item AdminEventRecord
|
|
if err := row.Scan(
|
|
&item.ID,
|
|
&item.PublicID,
|
|
&item.TenantID,
|
|
&item.Slug,
|
|
&item.DisplayName,
|
|
&item.Summary,
|
|
&item.Status,
|
|
&item.CurrentReleaseID,
|
|
); err != nil {
|
|
return nil, fmt.Errorf("update admin event: %w", err)
|
|
}
|
|
return &item, nil
|
|
}
|
|
|
|
func scanAdminEvent(row pgx.Row) (*AdminEventRecord, error) {
|
|
var item AdminEventRecord
|
|
err := row.Scan(
|
|
&item.ID,
|
|
&item.PublicID,
|
|
&item.TenantID,
|
|
&item.TenantCode,
|
|
&item.TenantName,
|
|
&item.Slug,
|
|
&item.DisplayName,
|
|
&item.Summary,
|
|
&item.Status,
|
|
&item.CurrentReleaseID,
|
|
&item.CurrentReleasePubID,
|
|
&item.ConfigLabel,
|
|
&item.ManifestURL,
|
|
&item.ManifestChecksum,
|
|
&item.RouteCode,
|
|
&item.PresentationID,
|
|
&item.PresentationName,
|
|
&item.PresentationType,
|
|
&item.ContentBundleID,
|
|
&item.ContentBundleName,
|
|
&item.ContentEntryURL,
|
|
&item.ContentAssetRootURL,
|
|
&item.CurrentPresentationID,
|
|
&item.CurrentPresentationName,
|
|
&item.CurrentPresentationType,
|
|
&item.CurrentContentBundleID,
|
|
&item.CurrentContentBundleName,
|
|
&item.CurrentContentEntryURL,
|
|
&item.CurrentContentAssetRootURL,
|
|
&item.CurrentRuntimeBindingID,
|
|
&item.CurrentPlaceID,
|
|
&item.CurrentMapAssetID,
|
|
&item.CurrentTileReleaseID,
|
|
&item.CurrentCourseSetID,
|
|
&item.CurrentCourseVariantID,
|
|
&item.CurrentCourseVariantName,
|
|
&item.CurrentRuntimeRouteCode,
|
|
)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, nil
|
|
}
|
|
if err != nil {
|
|
return nil, fmt.Errorf("scan admin event: %w", err)
|
|
}
|
|
return &item, nil
|
|
}
|
|
|
|
func scanAdminEventFromRows(rows pgx.Rows) (*AdminEventRecord, error) {
|
|
var item AdminEventRecord
|
|
err := rows.Scan(
|
|
&item.ID,
|
|
&item.PublicID,
|
|
&item.TenantID,
|
|
&item.TenantCode,
|
|
&item.TenantName,
|
|
&item.Slug,
|
|
&item.DisplayName,
|
|
&item.Summary,
|
|
&item.Status,
|
|
&item.CurrentReleaseID,
|
|
&item.CurrentReleasePubID,
|
|
&item.ConfigLabel,
|
|
&item.ManifestURL,
|
|
&item.ManifestChecksum,
|
|
&item.RouteCode,
|
|
&item.PresentationID,
|
|
&item.PresentationName,
|
|
&item.PresentationType,
|
|
&item.ContentBundleID,
|
|
&item.ContentBundleName,
|
|
&item.ContentEntryURL,
|
|
&item.ContentAssetRootURL,
|
|
&item.CurrentPresentationID,
|
|
&item.CurrentPresentationName,
|
|
&item.CurrentPresentationType,
|
|
&item.CurrentContentBundleID,
|
|
&item.CurrentContentBundleName,
|
|
&item.CurrentContentEntryURL,
|
|
&item.CurrentContentAssetRootURL,
|
|
&item.CurrentRuntimeBindingID,
|
|
&item.CurrentPlaceID,
|
|
&item.CurrentMapAssetID,
|
|
&item.CurrentTileReleaseID,
|
|
&item.CurrentCourseSetID,
|
|
&item.CurrentCourseVariantID,
|
|
&item.CurrentCourseVariantName,
|
|
&item.CurrentRuntimeRouteCode,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("scan admin event row: %w", err)
|
|
}
|
|
return &item, nil
|
|
}
|