This commit is contained in:
2025-07-18 10:03:58 -04:00
parent 4f01a6445f
commit 66f257609f
37 changed files with 845 additions and 704 deletions

View File

@ -1,167 +0,0 @@
import Foundation
import SwiftData
struct DataLoader {
static let logger = AppLogger(
subsystem: Bundle.main.bundleIdentifier ?? "dev.rzen.indie.Workouts",
category: "InitialData"
)
// Data structures for JSON decoding
private struct ExerciseTypeData: Codable {
let name: String
let descr: String
}
private struct MuscleGroupData: Codable {
let name: String
let descr: String
}
private struct MuscleData: Codable {
let name: String
let descr: String
let muscleGroup: String
}
private struct ExerciseData: Codable {
let name: String
let setup: String
let descr: String
let sets: Int
let reps: Int
let weight: Int
let type: String
let muscles: [String]
}
private struct SplitExerciseAssignmentData: Codable {
let exercise: String
let weight: Int
let sets: Int
let reps: Int
}
private struct SplitData: Codable {
let name: String
let intro: String
let splitExerciseAssignments: [SplitExerciseAssignmentData]
}
@MainActor
static func create(modelContext: ModelContext) {
logger.info("Creating initial data from JSON files")
// Load and insert data
do {
// Dictionaries to store references
var exerciseTypes: [String: ExerciseType] = [:]
var muscleGroups: [String: MuscleGroup] = [:]
var muscles: [String: Muscle] = [:]
var exercises: [String: Exercise] = [:]
// 1. Load Exercise Types
let exerciseTypeData = try loadJSON(forResource: "exercise-types", type: [ExerciseTypeData].self)
for typeData in exerciseTypeData {
let exerciseType = ExerciseType(name: typeData.name, descr: typeData.descr)
exerciseTypes[typeData.name] = exerciseType
modelContext.insert(exerciseType)
}
// 2. Load Muscle Groups
let muscleGroupData = try loadJSON(forResource: "muscle-groups", type: [MuscleGroupData].self)
for groupData in muscleGroupData {
let muscleGroup = MuscleGroup(name: groupData.name, descr: groupData.descr)
muscleGroups[groupData.name] = muscleGroup
modelContext.insert(muscleGroup)
}
// 3. Load Muscles
let muscleData = try loadJSON(forResource: "muscles", type: [MuscleData].self)
for data in muscleData {
// Find the muscle group for this muscle
if let muscleGroup = muscleGroups[data.muscleGroup] {
let muscle = Muscle(name: data.name, descr: data.descr, muscleGroup: muscleGroup)
muscles[data.name] = muscle
modelContext.insert(muscle)
} else {
logger.warning("Muscle group not found for muscle: \(data.name)")
}
}
// 4. Load Exercises
let exerciseData = try loadJSON(forResource: "exercises", type: [ExerciseData].self)
for data in exerciseData {
let exercise = Exercise(name: data.name, descr: data.descr)
// Set exercise type
if let type = exerciseTypes[data.type] {
exercise.type = type
} else {
logger.warning("Exercise type not found: \(data.type) for exercise: \(data.name)")
}
// Set muscles
var exerciseMuscles: [Muscle] = []
for muscleName in data.muscles {
if let muscle = muscles[muscleName] {
exerciseMuscles.append(muscle)
} else {
logger.warning("Muscle not found: \(muscleName) for exercise: \(data.name)")
}
}
exercise.muscles = exerciseMuscles
exercises[data.name] = exercise
modelContext.insert(exercise)
}
// 5. Load Splits and Exercise Assignments
let splitData = try loadJSON(forResource: "splits", type: [SplitData].self)
for data in splitData {
let split = Split(name: data.name, intro: data.intro)
modelContext.insert(split)
// Create exercise assignments for this split
for (index, assignment) in data.splitExerciseAssignments.enumerated() {
if let exercise = exercises[assignment.exercise] {
let splitAssignment = SplitExerciseAssignment(
order: index + 1, // 1-based ordering
sets: assignment.sets,
reps: assignment.reps,
weight: assignment.weight,
split: split,
exercise: exercise
)
modelContext.insert(splitAssignment)
} else {
logger.warning("Exercise not found: \(assignment.exercise) for split: \(data.name)")
}
}
}
// Save all the inserted data
try modelContext.save()
logger.info("Initial data loaded successfully from JSON files")
} catch {
logger.error("Failed to load initial data from JSON files: \(error.localizedDescription)")
}
}
// Helper method to load and decode JSON from a file
private static func loadJSON<T: Decodable>(forResource name: String, type: T.Type) throws -> T {
guard let url = Bundle.main.url(forResource: name, withExtension: "json") else {
logger.error("Could not find JSON file: \(name).json")
throw NSError(domain: "InitialData", code: 1, userInfo: [NSLocalizedDescriptionKey: "Could not find JSON file: \(name).json"])
}
do {
let data = try Data(contentsOf: url)
let decoder = JSONDecoder()
return try decoder.decode(T.self, from: data)
} catch {
logger.error("Failed to decode JSON file \(name).json: \(error.localizedDescription)")
throw error
}
}
}

View File

@ -4,10 +4,6 @@ enum SchemaV1: VersionedSchema {
static var versionIdentifier: Schema.Version = .init(1, 0, 0)
static var models: [any PersistentModel.Type] = [
Exercise.self,
ExerciseType.self,
Muscle.self,
MuscleGroup.self,
Split.self,
SplitExerciseAssignment.self,
Workout.self,

View File

@ -4,10 +4,6 @@ enum SchemaV2: VersionedSchema {
static var versionIdentifier: Schema.Version = .init(1, 0, 1)
static var models: [any PersistentModel.Type] = [
Exercise.self,
ExerciseType.self,
Muscle.self,
MuscleGroup.self,
Split.self,
SplitExerciseAssignment.self,
Workout.self,

View File

@ -4,10 +4,6 @@ enum SchemaV3: VersionedSchema {
static var versionIdentifier: Schema.Version = .init(1, 0, 2)
static var models: [any PersistentModel.Type] = [
Exercise.self,
ExerciseType.self,
Muscle.self,
MuscleGroup.self,
Split.self,
SplitExerciseAssignment.self,
Workout.self,

View File

@ -9,7 +9,7 @@ final class WorkoutsContainer {
static func create() -> ModelContainer {
// Using the current models directly without migration plan to avoid reference errors
let schema = Schema(SchemaV2.models)
let schema = Schema(SchemaV1.models)
let configuration = ModelConfiguration(cloudKitDatabase: .automatic)
let container = try! ModelContainer(for: schema, configurations: configuration)
return container
@ -20,13 +20,10 @@ final class WorkoutsContainer {
let configuration = ModelConfiguration(isStoredInMemoryOnly: true)
do {
let schema = Schema(SchemaV2.models)
let schema = Schema(SchemaV1.models)
let container = try ModelContainer(for: schema, configurations: configuration)
let context = ModelContext(container)
// Create default data for previews
DataLoader.create(modelContext: context)
return container
} catch {
fatalError("Failed to create preview ModelContainer: \(error.localizedDescription)")