import FoundationEssentials public struct Product: Codable, Sendable, Identifiable { public let code: String? public let productName: String? public let brands: String? public let quantity: String? public let imageFrontUrl: String? public let imageSmallUrl: String? public let ingredientsText: String? // Grades public let nutriscoreGrade: String? public let novaGroup: Int? // Nutriments public let nutriments: Nutriments? public let ingredients: [Ingredient]? // MARK: - Product-Misc public let additivesN: Int? public let checked: String? public let complete: Int? public let completeness: Float? public let ecoscoreGrade: String? // ... public let nutrientLevels: NutrientLevels? public var id: String { guard let code = code else { return UUID().uuidString } return code } private enum CodingKeys: String, CodingKey { case code case productName = "product_name" case brands case quantity case imageFrontUrl = "image_front_url" case imageSmallUrl = "image_small_url" case ingredientsText = "ingredients_text" case nutriscoreGrade = "nutriscore_grade" case ecoscoreGrade = "ecoscore_grade" case novaGroup = "nova_group" case nutriments case ingredients case complete case completeness case additivesN = "additives_n" case checked case nutrientLevels = "nutrient_levels" } public init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) code = try container.decodeIfPresent(String.self, forKey: .code) productName = try container.decodeIfPresent( String.self, forKey: .productName) brands = try container.decodeIfPresent(String.self, forKey: .brands) quantity = try container.decodeIfPresent(String.self, forKey: .quantity) imageFrontUrl = try container.decodeIfPresent( String.self, forKey: .imageFrontUrl) imageSmallUrl = try container.decodeIfPresent( String.self, forKey: .imageSmallUrl) ingredientsText = try container.decodeIfPresent( String.self, forKey: .ingredientsText) // Grades nutriscoreGrade = try container.decodeIfPresent( String.self, forKey: .nutriscoreGrade) novaGroup = try container.decodeIfPresent( Int.self, forKey: .novaGroup) // Nutriments nutriments = try container.decodeIfPresent( Nutriments.self, forKey: .nutriments) ingredients = try container.decodeIfPresent( [Ingredient].self, forKey: .ingredients) // MARK: - Product-Misc additivesN = try container.decodeIfPresent( Int.self, forKey: .additivesN) checked = try container.decodeIfPresent(String.self, forKey: .checked) complete = try container.decodeIfPresent(Int.self, forKey: .complete) completeness = try container.decodeFloatOrString(forKey: .completeness) ecoscoreGrade = try container.decodeIfPresent( String.self, forKey: .ecoscoreGrade) // ... nutrientLevels = try container.decodeIfPresent( NutrientLevels.self, forKey: .nutrientLevels) } }