package repository import ( "Yimaru-Backend/internal/domain" "Yimaru-Backend/internal/ports" "context" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgtype" ) func NewMobileAppVersionStore(s *Store) ports.MobileAppVersionStore { return s } func mobileAppVersionToDomain( id int64, platform string, versionName string, versionCode int32, updateType string, releaseNotes pgtype.Text, storeURL pgtype.Text, minSupported pgtype.Int4, status string, createdAt pgtype.Timestamptz, updatedAt pgtype.Timestamptz, ) domain.MobileAppVersion { var minSupportedPtr *int32 if minSupported.Valid { v := minSupported.Int32 minSupportedPtr = &v } return domain.MobileAppVersion{ ID: id, Platform: platform, VersionName: versionName, VersionCode: versionCode, UpdateType: updateType, ReleaseNotes: fromPgText(releaseNotes), StoreURL: fromPgText(storeURL), MinSupportedVersionCode: minSupportedPtr, Status: status, CreatedAt: createdAt.Time, UpdatedAt: timePtr(updatedAt), } } func scanMobileAppVersion(row pgx.Row) (domain.MobileAppVersion, error) { var ( id int64 platform string versionName string versionCode int32 updateType string releaseNotes pgtype.Text storeURL pgtype.Text minSupported pgtype.Int4 status string createdAt pgtype.Timestamptz updatedAt pgtype.Timestamptz ) if err := row.Scan(&id, &platform, &versionName, &versionCode, &updateType, &releaseNotes, &storeURL, &minSupported, &status, &createdAt, &updatedAt); err != nil { return domain.MobileAppVersion{}, err } return mobileAppVersionToDomain(id, platform, versionName, versionCode, updateType, releaseNotes, storeURL, minSupported, status, createdAt, updatedAt), nil } const mobileAppVersionSelectCols = ` id, platform, version_name, version_code, update_type, release_notes, store_url, min_supported_version_code, status, created_at, updated_at ` func (s *Store) CreateMobileAppVersion(ctx context.Context, input domain.CreateMobileAppVersionInput) (domain.MobileAppVersion, error) { updateType := domain.MobileAppUpdateTypeOptional if input.UpdateType != nil { updateType = *input.UpdateType } status := domain.MobileAppVersionStatusActive if input.Status != nil { status = *input.Status } row := s.conn.QueryRow(ctx, ` INSERT INTO mobile_app_versions ( platform, version_name, version_code, update_type, release_notes, store_url, min_supported_version_code, status ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING `+mobileAppVersionSelectCols, input.Platform, input.VersionName, input.VersionCode, updateType, toPgText(input.ReleaseNotes), toPgText(input.StoreURL), toPgInt4(input.MinSupportedVersionCode), status, ) return scanMobileAppVersion(row) } func (s *Store) UpdateMobileAppVersion(ctx context.Context, id int64, input domain.UpdateMobileAppVersionInput) (domain.MobileAppVersion, error) { releaseNotesSet := input.ReleaseNotes != nil var releaseNotesValue pgtype.Text if releaseNotesSet { releaseNotesValue = toPgText(input.ReleaseNotes) } storeURLSet := input.StoreURL != nil var storeURLValue pgtype.Text if storeURLSet { storeURLValue = toPgText(input.StoreURL) } minSupportedSet := input.MinSupportedVersionCode != nil var minSupportedValue pgtype.Int4 if minSupportedSet { minSupportedValue = toPgInt4(input.MinSupportedVersionCode) } row := s.conn.QueryRow(ctx, ` UPDATE mobile_app_versions SET version_name = COALESCE($2, version_name), version_code = COALESCE($3, version_code), update_type = COALESCE($4, update_type), release_notes = CASE WHEN $5::boolean THEN $6 ELSE release_notes END, store_url = CASE WHEN $7::boolean THEN $8 ELSE store_url END, min_supported_version_code = CASE WHEN $9::boolean THEN $10::int ELSE min_supported_version_code END, status = COALESCE($11, status), updated_at = NOW() WHERE id = $1 RETURNING `+mobileAppVersionSelectCols, id, input.VersionName, input.VersionCode, input.UpdateType, releaseNotesSet, releaseNotesValue, storeURLSet, storeURLValue, minSupportedSet, minSupportedValue, input.Status, ) return scanMobileAppVersion(row) } func (s *Store) GetMobileAppVersionByID(ctx context.Context, id int64) (domain.MobileAppVersion, error) { row := s.conn.QueryRow(ctx, ` SELECT `+mobileAppVersionSelectCols+` FROM mobile_app_versions WHERE id = $1 `, id) return scanMobileAppVersion(row) } func (s *Store) ListMobileAppVersions(ctx context.Context, platform *string, status *string, limit int32, offset int32) ([]domain.MobileAppVersion, int64, error) { rows, err := s.conn.Query(ctx, ` SELECT `+mobileAppVersionSelectCols+` FROM mobile_app_versions WHERE ($1::text IS NULL OR platform = $1) AND ($2::text IS NULL OR status = $2) ORDER BY platform ASC, version_code DESC, id DESC LIMIT $3 OFFSET $4 `, toPgText(platform), toPgText(status), limit, offset) if err != nil { return nil, 0, err } defer rows.Close() versions := make([]domain.MobileAppVersion, 0) for rows.Next() { var ( id int64 rowPlatform string versionName string versionCode int32 updateType string releaseNotes pgtype.Text storeURL pgtype.Text minSupported pgtype.Int4 rowStatus string createdAt pgtype.Timestamptz updatedAt pgtype.Timestamptz ) if err := rows.Scan(&id, &rowPlatform, &versionName, &versionCode, &updateType, &releaseNotes, &storeURL, &minSupported, &rowStatus, &createdAt, &updatedAt); err != nil { return nil, 0, err } versions = append(versions, mobileAppVersionToDomain(id, rowPlatform, versionName, versionCode, updateType, releaseNotes, storeURL, minSupported, rowStatus, createdAt, updatedAt)) } if err := rows.Err(); err != nil { return nil, 0, err } var totalCount int64 if err := s.conn.QueryRow(ctx, ` SELECT COUNT(*) FROM mobile_app_versions WHERE ($1::text IS NULL OR platform = $1) AND ($2::text IS NULL OR status = $2) `, toPgText(platform), toPgText(status)).Scan(&totalCount); err != nil { return nil, 0, err } return versions, totalCount, nil } func (s *Store) DeleteMobileAppVersion(ctx context.Context, id int64) error { cmd, err := s.conn.Exec(ctx, `DELETE FROM mobile_app_versions WHERE id = $1`, id) if err != nil { return err } if cmd.RowsAffected() == 0 { return pgx.ErrNoRows } return nil } func (s *Store) GetLatestActiveMobileAppVersion(ctx context.Context, platform string) (domain.MobileAppVersion, error) { row := s.conn.QueryRow(ctx, ` SELECT `+mobileAppVersionSelectCols+` FROM mobile_app_versions WHERE platform = $1 AND status = 'ACTIVE' ORDER BY version_code DESC, id DESC LIMIT 1 `, platform) return scanMobileAppVersion(row) }