chore: commit all pending changes
This commit is contained in:
@@ -10,7 +10,13 @@ import CloudKit
|
||||
|
||||
// MARK: - Record Type Constants
|
||||
|
||||
enum CKRecordType {
|
||||
private extension String {
|
||||
nonisolated var ckTrimmed: String {
|
||||
trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
}
|
||||
}
|
||||
|
||||
nonisolated enum CKRecordType {
|
||||
static let team = "Team"
|
||||
static let stadium = "Stadium"
|
||||
static let game = "Game"
|
||||
@@ -25,7 +31,7 @@ enum CKRecordType {
|
||||
|
||||
// MARK: - CKTeam
|
||||
|
||||
struct CKTeam {
|
||||
nonisolated struct CKTeam {
|
||||
static let idKey = "teamId"
|
||||
static let canonicalIdKey = "canonicalId"
|
||||
static let nameKey = "name"
|
||||
@@ -62,12 +68,22 @@ struct CKTeam {
|
||||
|
||||
/// The canonical ID string from CloudKit (e.g., "team_nba_atl")
|
||||
var canonicalId: String? {
|
||||
record[CKTeam.canonicalIdKey] as? String
|
||||
if let explicit = (record[CKTeam.canonicalIdKey] as? String)?.ckTrimmed, !explicit.isEmpty {
|
||||
return explicit
|
||||
}
|
||||
let fallback = record.recordID.recordName.ckTrimmed
|
||||
return fallback.isEmpty ? nil : fallback
|
||||
}
|
||||
|
||||
/// The stadium canonical ID string from CloudKit (e.g., "stadium_nba_state_farm_arena")
|
||||
var stadiumCanonicalId: String? {
|
||||
record[CKTeam.stadiumCanonicalIdKey] as? String
|
||||
if let explicit = (record[CKTeam.stadiumCanonicalIdKey] as? String)?.ckTrimmed, !explicit.isEmpty {
|
||||
return explicit
|
||||
}
|
||||
if let stadiumRef = record[CKTeam.stadiumRefKey] as? CKRecord.Reference {
|
||||
return stadiumRef.recordID.recordName.ckTrimmed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/// The conference canonical ID string from CloudKit (e.g., "nba_eastern")
|
||||
@@ -82,16 +98,18 @@ struct CKTeam {
|
||||
|
||||
var team: Team? {
|
||||
// Use teamId field, or fall back to record name
|
||||
let id = (record[CKTeam.idKey] as? String) ?? record.recordID.recordName
|
||||
let id = ((record[CKTeam.idKey] as? String)?.ckTrimmed) ?? record.recordID.recordName.ckTrimmed
|
||||
let abbreviation = (record[CKTeam.abbreviationKey] as? String)?.ckTrimmed
|
||||
let sportRaw = (record[CKTeam.sportKey] as? String)?.ckTrimmed
|
||||
let city = (record[CKTeam.cityKey] as? String)?.ckTrimmed
|
||||
guard !id.isEmpty,
|
||||
let abbreviation = record[CKTeam.abbreviationKey] as? String,
|
||||
let sportRaw = record[CKTeam.sportKey] as? String,
|
||||
let sport = Sport(rawValue: sportRaw),
|
||||
let city = record[CKTeam.cityKey] as? String
|
||||
let abbreviation, !abbreviation.isEmpty,
|
||||
let sportRaw, let sport = Sport(rawValue: sportRaw.uppercased()),
|
||||
let city, !city.isEmpty
|
||||
else { return nil }
|
||||
|
||||
// Name defaults to abbreviation if not provided
|
||||
let name = record[CKTeam.nameKey] as? String ?? abbreviation
|
||||
let name = ((record[CKTeam.nameKey] as? String)?.ckTrimmed).flatMap { $0.isEmpty ? nil : $0 } ?? abbreviation
|
||||
|
||||
// Stadium reference is optional - use placeholder string if not present
|
||||
let stadiumId: String
|
||||
@@ -122,7 +140,7 @@ struct CKTeam {
|
||||
|
||||
// MARK: - CKStadium
|
||||
|
||||
struct CKStadium {
|
||||
nonisolated struct CKStadium {
|
||||
static let idKey = "stadiumId"
|
||||
static let canonicalIdKey = "canonicalId"
|
||||
static let nameKey = "name"
|
||||
@@ -157,25 +175,31 @@ struct CKStadium {
|
||||
|
||||
/// The canonical ID string from CloudKit (e.g., "stadium_nba_state_farm_arena")
|
||||
var canonicalId: String? {
|
||||
record[CKStadium.canonicalIdKey] as? String
|
||||
if let explicit = (record[CKStadium.canonicalIdKey] as? String)?.ckTrimmed, !explicit.isEmpty {
|
||||
return explicit
|
||||
}
|
||||
let fallback = record.recordID.recordName.ckTrimmed
|
||||
return fallback.isEmpty ? nil : fallback
|
||||
}
|
||||
|
||||
var stadium: Stadium? {
|
||||
// Use stadiumId field, or fall back to record name
|
||||
let id = (record[CKStadium.idKey] as? String) ?? record.recordID.recordName
|
||||
let id = ((record[CKStadium.idKey] as? String)?.ckTrimmed) ?? record.recordID.recordName.ckTrimmed
|
||||
let name = (record[CKStadium.nameKey] as? String)?.ckTrimmed
|
||||
let city = (record[CKStadium.cityKey] as? String)?.ckTrimmed
|
||||
guard !id.isEmpty,
|
||||
let name = record[CKStadium.nameKey] as? String,
|
||||
let city = record[CKStadium.cityKey] as? String
|
||||
let name, !name.isEmpty,
|
||||
let city, !city.isEmpty
|
||||
else { return nil }
|
||||
|
||||
// These fields are optional in CloudKit
|
||||
let state = record[CKStadium.stateKey] as? String ?? ""
|
||||
let state = ((record[CKStadium.stateKey] as? String)?.ckTrimmed) ?? ""
|
||||
let location = record[CKStadium.locationKey] as? CLLocation
|
||||
let capacity = record[CKStadium.capacityKey] as? Int ?? 0
|
||||
let imageURL = (record[CKStadium.imageURLKey] as? String).flatMap { URL(string: $0) }
|
||||
let sportRaw = record[CKStadium.sportKey] as? String ?? "MLB"
|
||||
let sport = Sport(rawValue: sportRaw) ?? .mlb
|
||||
let timezoneIdentifier = record[CKStadium.timezoneIdentifierKey] as? String
|
||||
let sportRaw = ((record[CKStadium.sportKey] as? String)?.ckTrimmed).flatMap { $0.isEmpty ? nil : $0 } ?? "MLB"
|
||||
let sport = Sport(rawValue: sportRaw.uppercased()) ?? .mlb
|
||||
let timezoneIdentifier = (record[CKStadium.timezoneIdentifierKey] as? String)?.ckTrimmed
|
||||
|
||||
return Stadium(
|
||||
id: id,
|
||||
@@ -195,7 +219,7 @@ struct CKStadium {
|
||||
|
||||
// MARK: - CKGame
|
||||
|
||||
struct CKGame {
|
||||
nonisolated struct CKGame {
|
||||
static let idKey = "gameId"
|
||||
static let canonicalIdKey = "canonicalId"
|
||||
static let homeTeamRefKey = "homeTeamRef"
|
||||
@@ -232,31 +256,64 @@ struct CKGame {
|
||||
|
||||
/// The canonical ID string from CloudKit (e.g., "game_nba_202526_20251021_hou_okc")
|
||||
var canonicalId: String? {
|
||||
record[CKGame.canonicalIdKey] as? String
|
||||
if let explicit = (record[CKGame.canonicalIdKey] as? String)?.ckTrimmed, !explicit.isEmpty {
|
||||
return explicit
|
||||
}
|
||||
let fallback = record.recordID.recordName.ckTrimmed
|
||||
return fallback.isEmpty ? nil : fallback
|
||||
}
|
||||
|
||||
/// The home team canonical ID string from CloudKit (e.g., "team_nba_okc")
|
||||
var homeTeamCanonicalId: String? {
|
||||
record[CKGame.homeTeamCanonicalIdKey] as? String
|
||||
if let explicit = (record[CKGame.homeTeamCanonicalIdKey] as? String)?.ckTrimmed, !explicit.isEmpty {
|
||||
return explicit
|
||||
}
|
||||
if let homeRef = record[CKGame.homeTeamRefKey] as? CKRecord.Reference {
|
||||
return homeRef.recordID.recordName.ckTrimmed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/// The away team canonical ID string from CloudKit (e.g., "team_nba_hou")
|
||||
var awayTeamCanonicalId: String? {
|
||||
record[CKGame.awayTeamCanonicalIdKey] as? String
|
||||
if let explicit = (record[CKGame.awayTeamCanonicalIdKey] as? String)?.ckTrimmed, !explicit.isEmpty {
|
||||
return explicit
|
||||
}
|
||||
if let awayRef = record[CKGame.awayTeamRefKey] as? CKRecord.Reference {
|
||||
return awayRef.recordID.recordName.ckTrimmed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/// The stadium canonical ID string from CloudKit (e.g., "stadium_nba_paycom_center")
|
||||
var stadiumCanonicalId: String? {
|
||||
record[CKGame.stadiumCanonicalIdKey] as? String
|
||||
if let explicit = (record[CKGame.stadiumCanonicalIdKey] as? String)?.ckTrimmed, !explicit.isEmpty {
|
||||
return explicit
|
||||
}
|
||||
if let stadiumRef = record[CKGame.stadiumRefKey] as? CKRecord.Reference {
|
||||
return stadiumRef.recordID.recordName.ckTrimmed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func game(homeTeamId: String, awayTeamId: String, stadiumId: String) -> Game? {
|
||||
let id = (record[CKGame.idKey] as? String) ?? record.recordID.recordName
|
||||
let id = ((record[CKGame.idKey] as? String)?.ckTrimmed) ?? record.recordID.recordName.ckTrimmed
|
||||
let sportRaw = (record[CKGame.sportKey] as? String)?.ckTrimmed
|
||||
let season: String
|
||||
if let seasonString = (record[CKGame.seasonKey] as? String)?.ckTrimmed, !seasonString.isEmpty {
|
||||
season = seasonString
|
||||
} else if let seasonInt = record[CKGame.seasonKey] as? Int {
|
||||
season = String(seasonInt)
|
||||
} else if let seasonInt64 = record[CKGame.seasonKey] as? Int64 {
|
||||
season = String(seasonInt64)
|
||||
} else if let seasonNumber = record[CKGame.seasonKey] as? NSNumber {
|
||||
season = seasonNumber.stringValue
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
guard !id.isEmpty,
|
||||
let dateTime = record[CKGame.dateTimeKey] as? Date,
|
||||
let sportRaw = record[CKGame.sportKey] as? String,
|
||||
let sport = Sport(rawValue: sportRaw),
|
||||
let season = record[CKGame.seasonKey] as? String
|
||||
let sportRaw, let sport = Sport(rawValue: sportRaw.uppercased())
|
||||
else { return nil }
|
||||
|
||||
return Game(
|
||||
@@ -267,7 +324,13 @@ struct CKGame {
|
||||
dateTime: dateTime,
|
||||
sport: sport,
|
||||
season: season,
|
||||
isPlayoff: (record[CKGame.isPlayoffKey] as? Int) == 1,
|
||||
isPlayoff: {
|
||||
if let value = record[CKGame.isPlayoffKey] as? Int { return value == 1 }
|
||||
if let value = record[CKGame.isPlayoffKey] as? Int64 { return value == 1 }
|
||||
if let value = record[CKGame.isPlayoffKey] as? NSNumber { return value.intValue == 1 }
|
||||
if let value = record[CKGame.isPlayoffKey] as? Bool { return value }
|
||||
return false
|
||||
}(),
|
||||
broadcastInfo: record[CKGame.broadcastInfoKey] as? String
|
||||
)
|
||||
}
|
||||
@@ -275,7 +338,7 @@ struct CKGame {
|
||||
|
||||
// MARK: - CKLeagueStructure
|
||||
|
||||
struct CKLeagueStructure {
|
||||
nonisolated struct CKLeagueStructure {
|
||||
static let idKey = "structureId"
|
||||
static let sportKey = "sport"
|
||||
static let typeKey = "type"
|
||||
@@ -308,15 +371,18 @@ struct CKLeagueStructure {
|
||||
|
||||
/// Convert to SwiftData model for local storage
|
||||
func toModel() -> LeagueStructureModel? {
|
||||
guard let id = record[CKLeagueStructure.idKey] as? String,
|
||||
let sport = record[CKLeagueStructure.sportKey] as? String,
|
||||
let id = ((record[CKLeagueStructure.idKey] as? String)?.ckTrimmed) ?? record.recordID.recordName.ckTrimmed
|
||||
let sport = (record[CKLeagueStructure.sportKey] as? String)?.ckTrimmed.uppercased()
|
||||
guard !id.isEmpty,
|
||||
let sport, !sport.isEmpty,
|
||||
let typeRaw = record[CKLeagueStructure.typeKey] as? String,
|
||||
let structureType = LeagueStructureType(rawValue: typeRaw),
|
||||
let name = record[CKLeagueStructure.nameKey] as? String
|
||||
let structureType = LeagueStructureType(rawValue: typeRaw.lowercased()),
|
||||
let name = (record[CKLeagueStructure.nameKey] as? String)?.ckTrimmed,
|
||||
!name.isEmpty
|
||||
else { return nil }
|
||||
|
||||
let abbreviation = record[CKLeagueStructure.abbreviationKey] as? String
|
||||
let parentId = record[CKLeagueStructure.parentIdKey] as? String
|
||||
let abbreviation = (record[CKLeagueStructure.abbreviationKey] as? String)?.ckTrimmed
|
||||
let parentId = (record[CKLeagueStructure.parentIdKey] as? String)?.ckTrimmed
|
||||
let displayOrder = record[CKLeagueStructure.displayOrderKey] as? Int ?? 0
|
||||
let schemaVersion = record[CKLeagueStructure.schemaVersionKey] as? Int ?? SchemaVersion.current
|
||||
let lastModified = record[CKLeagueStructure.lastModifiedKey] as? Date ?? record.modificationDate ?? Date()
|
||||
@@ -337,7 +403,7 @@ struct CKLeagueStructure {
|
||||
|
||||
// MARK: - CKSport
|
||||
|
||||
struct CKSport {
|
||||
nonisolated struct CKSport {
|
||||
static let idKey = "sportId"
|
||||
static let abbreviationKey = "abbreviation"
|
||||
static let displayNameKey = "displayName"
|
||||
@@ -357,16 +423,49 @@ struct CKSport {
|
||||
|
||||
/// Convert to CanonicalSport for local storage
|
||||
func toCanonical() -> CanonicalSport? {
|
||||
guard let id = record[CKSport.idKey] as? String,
|
||||
let abbreviation = record[CKSport.abbreviationKey] as? String,
|
||||
let displayName = record[CKSport.displayNameKey] as? String,
|
||||
let iconName = record[CKSport.iconNameKey] as? String,
|
||||
let colorHex = record[CKSport.colorHexKey] as? String,
|
||||
let seasonStartMonth = record[CKSport.seasonStartMonthKey] as? Int,
|
||||
let seasonEndMonth = record[CKSport.seasonEndMonthKey] as? Int
|
||||
let id = ((record[CKSport.idKey] as? String)?.ckTrimmed) ?? record.recordID.recordName.ckTrimmed
|
||||
let seasonStartMonth: Int?
|
||||
if let intValue = record[CKSport.seasonStartMonthKey] as? Int {
|
||||
seasonStartMonth = intValue
|
||||
} else if let int64Value = record[CKSport.seasonStartMonthKey] as? Int64 {
|
||||
seasonStartMonth = Int(int64Value)
|
||||
} else if let numberValue = record[CKSport.seasonStartMonthKey] as? NSNumber {
|
||||
seasonStartMonth = numberValue.intValue
|
||||
} else {
|
||||
seasonStartMonth = nil
|
||||
}
|
||||
|
||||
let seasonEndMonth: Int?
|
||||
if let intValue = record[CKSport.seasonEndMonthKey] as? Int {
|
||||
seasonEndMonth = intValue
|
||||
} else if let int64Value = record[CKSport.seasonEndMonthKey] as? Int64 {
|
||||
seasonEndMonth = Int(int64Value)
|
||||
} else if let numberValue = record[CKSport.seasonEndMonthKey] as? NSNumber {
|
||||
seasonEndMonth = numberValue.intValue
|
||||
} else {
|
||||
seasonEndMonth = nil
|
||||
}
|
||||
|
||||
guard !id.isEmpty,
|
||||
let abbreviation = (record[CKSport.abbreviationKey] as? String)?.ckTrimmed,
|
||||
!abbreviation.isEmpty,
|
||||
let displayName = (record[CKSport.displayNameKey] as? String)?.ckTrimmed,
|
||||
!displayName.isEmpty,
|
||||
let iconName = (record[CKSport.iconNameKey] as? String)?.ckTrimmed,
|
||||
!iconName.isEmpty,
|
||||
let colorHex = (record[CKSport.colorHexKey] as? String)?.ckTrimmed,
|
||||
!colorHex.isEmpty,
|
||||
let seasonStartMonth,
|
||||
let seasonEndMonth
|
||||
else { return nil }
|
||||
|
||||
let isActive = (record[CKSport.isActiveKey] as? Int ?? 1) == 1
|
||||
let isActive: Bool = {
|
||||
if let value = record[CKSport.isActiveKey] as? Int { return value == 1 }
|
||||
if let value = record[CKSport.isActiveKey] as? Int64 { return value == 1 }
|
||||
if let value = record[CKSport.isActiveKey] as? NSNumber { return value.intValue == 1 }
|
||||
if let value = record[CKSport.isActiveKey] as? Bool { return value }
|
||||
return true
|
||||
}()
|
||||
let schemaVersion = record[CKSport.schemaVersionKey] as? Int ?? SchemaVersion.current
|
||||
let lastModified = record[CKSport.lastModifiedKey] as? Date ?? record.modificationDate ?? Date()
|
||||
|
||||
@@ -388,7 +487,7 @@ struct CKSport {
|
||||
|
||||
// MARK: - CKStadiumAlias
|
||||
|
||||
struct CKStadiumAlias {
|
||||
nonisolated struct CKStadiumAlias {
|
||||
static let aliasNameKey = "aliasName"
|
||||
static let stadiumCanonicalIdKey = "stadiumCanonicalId"
|
||||
static let validFromKey = "validFrom"
|
||||
@@ -415,8 +514,10 @@ struct CKStadiumAlias {
|
||||
|
||||
/// Convert to SwiftData model for local storage
|
||||
func toModel() -> StadiumAlias? {
|
||||
guard let aliasName = record[CKStadiumAlias.aliasNameKey] as? String,
|
||||
let stadiumCanonicalId = record[CKStadiumAlias.stadiumCanonicalIdKey] as? String
|
||||
let aliasName = ((record[CKStadiumAlias.aliasNameKey] as? String)?.ckTrimmed) ?? record.recordID.recordName.ckTrimmed
|
||||
guard !aliasName.isEmpty,
|
||||
let stadiumCanonicalId = (record[CKStadiumAlias.stadiumCanonicalIdKey] as? String)?.ckTrimmed,
|
||||
!stadiumCanonicalId.isEmpty
|
||||
else { return nil }
|
||||
|
||||
let validFrom = record[CKStadiumAlias.validFromKey] as? Date
|
||||
@@ -437,7 +538,7 @@ struct CKStadiumAlias {
|
||||
|
||||
// MARK: - CKTeamAlias
|
||||
|
||||
struct CKTeamAlias {
|
||||
nonisolated struct CKTeamAlias {
|
||||
static let idKey = "aliasId"
|
||||
static let teamCanonicalIdKey = "teamCanonicalId"
|
||||
static let aliasTypeKey = "aliasType"
|
||||
@@ -468,11 +569,14 @@ struct CKTeamAlias {
|
||||
|
||||
/// Convert to SwiftData model for local storage
|
||||
func toModel() -> TeamAlias? {
|
||||
guard let id = record[CKTeamAlias.idKey] as? String,
|
||||
let teamCanonicalId = record[CKTeamAlias.teamCanonicalIdKey] as? String,
|
||||
let aliasTypeRaw = record[CKTeamAlias.aliasTypeKey] as? String,
|
||||
let aliasType = TeamAliasType(rawValue: aliasTypeRaw),
|
||||
let aliasValue = record[CKTeamAlias.aliasValueKey] as? String
|
||||
let id = ((record[CKTeamAlias.idKey] as? String)?.ckTrimmed) ?? record.recordID.recordName.ckTrimmed
|
||||
guard !id.isEmpty,
|
||||
let teamCanonicalId = (record[CKTeamAlias.teamCanonicalIdKey] as? String)?.ckTrimmed,
|
||||
!teamCanonicalId.isEmpty,
|
||||
let aliasTypeRaw = (record[CKTeamAlias.aliasTypeKey] as? String)?.ckTrimmed,
|
||||
let aliasType = TeamAliasType(rawValue: aliasTypeRaw.lowercased()),
|
||||
let aliasValue = (record[CKTeamAlias.aliasValueKey] as? String)?.ckTrimmed,
|
||||
!aliasValue.isEmpty
|
||||
else { return nil }
|
||||
|
||||
let validFrom = record[CKTeamAlias.validFromKey] as? Date
|
||||
@@ -495,7 +599,7 @@ struct CKTeamAlias {
|
||||
|
||||
// MARK: - CKTripPoll
|
||||
|
||||
struct CKTripPoll {
|
||||
nonisolated struct CKTripPoll {
|
||||
static let pollIdKey = "pollId"
|
||||
static let titleKey = "title"
|
||||
static let ownerIdKey = "ownerId"
|
||||
@@ -594,7 +698,7 @@ struct CKTripPoll {
|
||||
|
||||
// MARK: - CKPollVote
|
||||
|
||||
struct CKPollVote {
|
||||
nonisolated struct CKPollVote {
|
||||
static let voteIdKey = "voteId"
|
||||
static let pollIdKey = "pollId"
|
||||
static let voterIdKey = "voterId"
|
||||
@@ -640,4 +744,3 @@ struct CKPollVote {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user