Better handling of Nutriments
This commit is contained in:
69
.swift-format
Normal file
69
.swift-format
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
{
|
||||||
|
"fileScopedDeclarationPrivacy" : {
|
||||||
|
"accessLevel" : "private"
|
||||||
|
},
|
||||||
|
"indentation" : {
|
||||||
|
"tabs" : 1
|
||||||
|
},
|
||||||
|
"indentConditionalCompilationBlocks" : true,
|
||||||
|
"indentSwitchCaseLabels" : false,
|
||||||
|
"lineBreakAroundMultilineExpressionChainComponents" : false,
|
||||||
|
"lineBreakBeforeControlFlowKeywords" : false,
|
||||||
|
"lineBreakBeforeEachArgument" : false,
|
||||||
|
"lineBreakBeforeEachGenericRequirement" : false,
|
||||||
|
"lineLength" : 80,
|
||||||
|
"maximumBlankLines" : 1,
|
||||||
|
"multiElementCollectionTrailingCommas" : true,
|
||||||
|
"noAssignmentInExpressions" : {
|
||||||
|
"allowedFunctions" : [
|
||||||
|
"XCTAssertNoThrow"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"prioritizeKeepingFunctionOutputTogether" : false,
|
||||||
|
"respectsExistingLineBreaks" : true,
|
||||||
|
"rules" : {
|
||||||
|
"AllPublicDeclarationsHaveDocumentation" : false,
|
||||||
|
"AlwaysUseLiteralForEmptyCollectionInit" : false,
|
||||||
|
"AlwaysUseLowerCamelCase" : true,
|
||||||
|
"AmbiguousTrailingClosureOverload" : true,
|
||||||
|
"BeginDocumentationCommentWithOneLineSummary" : false,
|
||||||
|
"DoNotUseSemicolons" : true,
|
||||||
|
"DontRepeatTypeInStaticProperties" : true,
|
||||||
|
"FileScopedDeclarationPrivacy" : true,
|
||||||
|
"FullyIndirectEnum" : true,
|
||||||
|
"GroupNumericLiterals" : true,
|
||||||
|
"IdentifiersMustBeASCII" : true,
|
||||||
|
"NeverForceUnwrap" : false,
|
||||||
|
"NeverUseForceTry" : false,
|
||||||
|
"NeverUseImplicitlyUnwrappedOptionals" : false,
|
||||||
|
"NoAccessLevelOnExtensionDeclaration" : true,
|
||||||
|
"NoAssignmentInExpressions" : true,
|
||||||
|
"NoBlockComments" : true,
|
||||||
|
"NoCasesWithOnlyFallthrough" : true,
|
||||||
|
"NoEmptyTrailingClosureParentheses" : true,
|
||||||
|
"NoLabelsInCasePatterns" : true,
|
||||||
|
"NoLeadingUnderscores" : false,
|
||||||
|
"NoParensAroundConditions" : true,
|
||||||
|
"NoPlaygroundLiterals" : true,
|
||||||
|
"NoVoidReturnOnFunctionSignature" : true,
|
||||||
|
"OmitExplicitReturns" : false,
|
||||||
|
"OneCasePerLine" : true,
|
||||||
|
"OneVariableDeclarationPerLine" : true,
|
||||||
|
"OnlyOneTrailingClosureArgument" : true,
|
||||||
|
"OrderedImports" : true,
|
||||||
|
"ReplaceForEachWithForLoop" : true,
|
||||||
|
"ReturnVoidInsteadOfEmptyTuple" : true,
|
||||||
|
"TypeNamesShouldBeCapitalized" : true,
|
||||||
|
"UseEarlyExits" : false,
|
||||||
|
"UseLetInEveryBoundCaseVariable" : true,
|
||||||
|
"UseShorthandTypeNames" : true,
|
||||||
|
"UseSingleLinePropertyGetter" : true,
|
||||||
|
"UseSynthesizedInitializer" : true,
|
||||||
|
"UseTripleSlashForDocumentationComments" : true,
|
||||||
|
"UseWhereClausesInForLoops" : false,
|
||||||
|
"ValidateDocumentationComments" : false
|
||||||
|
},
|
||||||
|
"spacesAroundRangeFormationOperators" : false,
|
||||||
|
"tabWidth" : 4,
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
15
Package.resolved
Normal file
15
Package.resolved
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"originHash" : "45ae84ae5c5095f4d85c870c36fff7e4577f267c4a02fa550762071d2f9eca53",
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "swift-units",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "git@git.cems.dev:cdricms/swift-units.git",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "master",
|
||||||
|
"revision" : "0962ae290044d24722610234cb215b748722f196"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 3
|
||||||
|
}
|
||||||
@@ -1,30 +1,38 @@
|
|||||||
// swift-tools-version: 5.9
|
// swift-tools-version: 6.1
|
||||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
import PackageDescription
|
import PackageDescription
|
||||||
|
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "swift-openfoodfacts-sdk",
|
name: "swift-openfoodfacts-sdk",
|
||||||
platforms: [
|
platforms: [
|
||||||
.macOS(.v14),
|
.macOS(.v14),
|
||||||
.iOS(.v15),
|
.iOS(.v15),
|
||||||
],
|
],
|
||||||
products: [
|
products: [
|
||||||
// Products define the executables and libraries a package produces, making them visible to other packages.
|
// Products define the executables and libraries a package produces, making them visible to other packages.
|
||||||
.library(
|
.library(
|
||||||
name: "OpenFoodFacts",
|
name: "OpenFoodFacts",
|
||||||
targets: ["OpenFoodFacts"]
|
targets: ["OpenFoodFacts"]
|
||||||
),
|
)
|
||||||
],
|
],
|
||||||
targets: [
|
dependencies: [
|
||||||
// Targets are the basic building blocks of a package, defining a module or a test suite.
|
.package(
|
||||||
// Targets can depend on other targets in this package and products from dependencies.
|
url: "git@git.cems.dev:cdricms/swift-units.git", branch: "master")
|
||||||
.target(
|
],
|
||||||
name: "OpenFoodFacts", path: "Sources/OpenFoodFacts"
|
targets: [
|
||||||
),
|
// Targets are the basic building blocks of a package, defining a module or a test suite.
|
||||||
.testTarget(
|
// Targets can depend on other targets in this package and products from dependencies.
|
||||||
name: "OpenFoodFactsTests",
|
.target(
|
||||||
dependencies: ["OpenFoodFacts"]
|
name: "OpenFoodFacts",
|
||||||
),
|
dependencies: [
|
||||||
]
|
.product(name: "Units", package: "swift-units")
|
||||||
|
],
|
||||||
|
path: "Sources/OpenFoodFacts",
|
||||||
|
),
|
||||||
|
.testTarget(
|
||||||
|
name: "OpenFoodFactsTests",
|
||||||
|
dependencies: ["OpenFoodFacts"]
|
||||||
|
),
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
extension String {
|
extension String {
|
||||||
func camelCaseToSnakeCase() -> String {
|
func camelCaseToSnakeCase() -> String {
|
||||||
var result = ""
|
var result = ""
|
||||||
var lastCharacterWasUppercase = false
|
var lastCharacterWasUppercase = false
|
||||||
|
|
||||||
for character in self {
|
for character in self {
|
||||||
if character.isUppercase {
|
if character.isUppercase {
|
||||||
if !result.isEmpty && !lastCharacterWasUppercase {
|
if !result.isEmpty && !lastCharacterWasUppercase {
|
||||||
result.append("_")
|
result.append("_")
|
||||||
}
|
}
|
||||||
result.append(character.lowercased())
|
result.append(character.lowercased())
|
||||||
lastCharacterWasUppercase = true
|
lastCharacterWasUppercase = true
|
||||||
} else {
|
} else {
|
||||||
result.append(character)
|
result.append(character)
|
||||||
lastCharacterWasUppercase = false
|
lastCharacterWasUppercase = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,84 +4,97 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class OpenFoodFactsClient {
|
public class OpenFoodFactsClient {
|
||||||
let version: Int = 0
|
let version: Int = 0
|
||||||
public var prod: Bool = false
|
public var prod: Bool = false
|
||||||
var baseURL: URL? {
|
var baseURL: URL? {
|
||||||
if prod {
|
if prod {
|
||||||
return URL(string: "https://world.openfoodfacts.org/api/v\(version)")
|
return URL(
|
||||||
} else {
|
string: "https://world.openfoodfacts.org/api/v\(version)")
|
||||||
return URL(string: "https://world.openfoodfacts.net/api/v\(version)")
|
} else {
|
||||||
}
|
return URL(
|
||||||
}
|
string: "https://world.openfoodfacts.net/api/v\(version)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public init() {}
|
public init() {}
|
||||||
|
|
||||||
public func getProductByBarcode(_ barcode: String) async throws -> ProductResponse {
|
public func getProductByBarcode(_ barcode: String) async throws
|
||||||
guard let endpoint = baseURL?.appendingPathComponent("product/\(barcode)") else { throw OFFError.invalidURL }
|
-> ProductResponse
|
||||||
var request = URLRequest(url: endpoint)
|
{
|
||||||
request.setValue("application/json", forHTTPHeaderField: "accept")
|
guard
|
||||||
let (data, response) = try await URLSession.shared.data(for: request)
|
let endpoint = baseURL?.appendingPathComponent("product/\(barcode)")
|
||||||
|
else { throw OFFError.invalidURL }
|
||||||
|
var request = URLRequest(url: endpoint)
|
||||||
|
request.setValue("application/json", forHTTPHeaderField: "accept")
|
||||||
|
let (data, response) = try await URLSession.shared.data(for: request)
|
||||||
|
|
||||||
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
|
guard let response = response as? HTTPURLResponse,
|
||||||
throw OFFError.invalidResponse
|
response.statusCode == 200
|
||||||
}
|
else {
|
||||||
do {
|
throw OFFError.invalidResponse
|
||||||
return try JSONDecoder().decode(ProductResponse.self, from: data)
|
}
|
||||||
}
|
do {
|
||||||
}
|
return try JSONDecoder().decode(ProductResponse.self, from: data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public struct SearchQuery {
|
public struct SearchQuery {
|
||||||
public let additivesTags: String?
|
public let additivesTags: String?
|
||||||
public let allergensTags: String?
|
public let allergensTags: String?
|
||||||
public let brandsTags: String?
|
public let brandsTags: String?
|
||||||
public let categoriesTags: String?
|
public let categoriesTags: String?
|
||||||
public let countriesTagsEn: String?
|
public let countriesTagsEn: String?
|
||||||
public let embCodesTags: String?
|
public let embCodesTags: String?
|
||||||
public let labelsTags: String?
|
public let labelsTags: String?
|
||||||
public let manufacturingPlacesTags: String?
|
public let manufacturingPlacesTags: String?
|
||||||
public let nutritionGradesTags: String?
|
public let nutritionGradesTags: String?
|
||||||
public let originsTags: String?
|
public let originsTags: String?
|
||||||
public let packagingTagsDe: String?
|
public let packagingTagsDe: String?
|
||||||
public let purchasePlacesTags: String?
|
public let purchasePlacesTags: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
// public func search(_ productName: String, queryParams: SearchQuery? = nil) async throws -> SearchResponse {
|
// public func search(_ productName: String, queryParams: SearchQuery? = nil) async throws -> SearchResponse {
|
||||||
// let qp = Mirror(reflecting: queryParams ?? {})
|
// let qp = Mirror(reflecting: queryParams ?? {})
|
||||||
// var s: String = "?product_name=\(productName)&"
|
// var s: String = "?product_name=\(productName)&"
|
||||||
// for case let (label?, value) in qp.children {
|
// for case let (label?, value) in qp.children {
|
||||||
// s += label.camelCaseToSnakeCase() + "=" + (value as! String) + "&"
|
// s += label.camelCaseToSnakeCase() + "=" + (value as! String) + "&"
|
||||||
// }
|
// }
|
||||||
// guard let endpoint = baseURL?.appendingPathComponent("search\(s)") else { throw OFFError.invalidURL }
|
// guard let endpoint = baseURL?.appendingPathComponent("search\(s)") else { throw OFFError.invalidURL }
|
||||||
// var request = URLRequest(url: endpoint)
|
// var request = URLRequest(url: endpoint)
|
||||||
// request.setValue("application/json", forHTTPHeaderField: "accept")
|
// request.setValue("application/json", forHTTPHeaderField: "accept")
|
||||||
|
|
||||||
// let (data, response) = try await URLSession.shared.data(for: request)
|
// let (data, response) = try await URLSession.shared.data(for: request)
|
||||||
// guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
|
// guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
|
||||||
// throw OFFError.invalidResponse
|
// throw OFFError.invalidResponse
|
||||||
// }
|
// }
|
||||||
// do {
|
// do {
|
||||||
// return try JSONDecoder().decode(SearchResponse.self, from: data)
|
// return try JSONDecoder().decode(SearchResponse.self, from: data)
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
//https://wiki.openfoodfacts.org/API/Read/Search#Parameters
|
//https://wiki.openfoodfacts.org/API/Read/Search#Parameters
|
||||||
public func search(query: PerlSearchQuery) async throws -> SearchResponse {
|
public func search(query: PerlSearchQuery) async throws -> SearchResponse {
|
||||||
let endpoint = URL(string: "https://world.openfoodfacts.org/cgi/search.pl?\(query.makeToRequest())")!
|
let endpoint = URL(
|
||||||
print(endpoint)
|
string:
|
||||||
let request = URLRequest(url: endpoint)
|
"https://world.openfoodfacts.org/cgi/search.pl?\(query.makeToRequest())"
|
||||||
// request.setValue("application/json", forHTTPHeaderField: "accept")
|
)!
|
||||||
let (data, response) = try await URLSession.shared.data(for: request)
|
print(endpoint)
|
||||||
|
let request = URLRequest(url: endpoint)
|
||||||
|
// request.setValue("application/json", forHTTPHeaderField: "accept")
|
||||||
|
let (data, response) = try await URLSession.shared.data(for: request)
|
||||||
|
|
||||||
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
|
guard let response = response as? HTTPURLResponse,
|
||||||
throw OFFError.invalidResponse
|
response.statusCode == 200
|
||||||
}
|
else {
|
||||||
do {
|
throw OFFError.invalidResponse
|
||||||
return try JSONDecoder().decode(SearchResponse.self, from: data)
|
}
|
||||||
}
|
do {
|
||||||
|
return try JSONDecoder().decode(SearchResponse.self, from: data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum OFFError: Error {
|
enum OFFError: Error {
|
||||||
case invalidURL, invalidResponse
|
case invalidURL, invalidResponse
|
||||||
}
|
}
|
||||||
|
|||||||
15
Sources/OpenFoodFacts/Schemas/Images.swift
Normal file
15
Sources/OpenFoodFacts/Schemas/Images.swift
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
public struct Images: Codable {
|
||||||
|
public var otherData: [String: Data] = [:]
|
||||||
|
|
||||||
|
mutating func setDetail<T: Encodable>(key: String, value: T) throws {
|
||||||
|
let encodedValue = try JSONEncoder().encode(value)
|
||||||
|
otherData[key] = encodedValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDetail<T: Decodable>(key: String, type: T.Type) throws -> T? {
|
||||||
|
guard let data = otherData[key] else { return nil }
|
||||||
|
return try JSONDecoder().decode(type, from: data)
|
||||||
|
}
|
||||||
|
}
|
||||||
21
Sources/OpenFoodFacts/Schemas/Ingredient.swift
Normal file
21
Sources/OpenFoodFacts/Schemas/Ingredient.swift
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
public struct Ingredient: Codable, ObjectDebugger {
|
||||||
|
public var fromPalmOil: String? = nil
|
||||||
|
public var id: String? = nil
|
||||||
|
public var origin: String? = nil
|
||||||
|
public var percent: Float? = nil
|
||||||
|
public var rank: Float? = 0
|
||||||
|
public var text: String? = nil
|
||||||
|
public var vegan: String? = nil
|
||||||
|
public var vegetarian: String? = nil
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case fromPalmOil = "from_palm_oil"
|
||||||
|
case id
|
||||||
|
case origin
|
||||||
|
case percent
|
||||||
|
case rank
|
||||||
|
case text
|
||||||
|
case vegan
|
||||||
|
case vegetarian
|
||||||
|
}
|
||||||
|
}
|
||||||
5
Sources/OpenFoodFacts/Schemas/LanguagesCodes.swift
Normal file
5
Sources/OpenFoodFacts/Schemas/LanguagesCodes.swift
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
public struct LanguagesCodes: Codable, ObjectDebugger {
|
||||||
|
public var en: Float? = nil
|
||||||
|
public var fr: Float? = nil
|
||||||
|
public var pl: Float? = nil
|
||||||
|
}
|
||||||
13
Sources/OpenFoodFacts/Schemas/NutrientLevels.swift
Normal file
13
Sources/OpenFoodFacts/Schemas/NutrientLevels.swift
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
public struct NutrientLevels: Codable, ObjectDebugger {
|
||||||
|
public var fat: String? = nil
|
||||||
|
public var salt: String? = nil
|
||||||
|
public var saturatedFat: String? = nil
|
||||||
|
public var sugars: String? = nil
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case fat
|
||||||
|
case salt
|
||||||
|
case saturatedFat = "saturated-fat"
|
||||||
|
case sugars
|
||||||
|
}
|
||||||
|
}
|
||||||
239
Sources/OpenFoodFacts/Schemas/Nutriments.swift
Normal file
239
Sources/OpenFoodFacts/Schemas/Nutriments.swift
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
import Foundation
|
||||||
|
import Units
|
||||||
|
|
||||||
|
@dynamicMemberLookup
|
||||||
|
public struct Nutriments: Codable, ObjectDebugger {
|
||||||
|
private var nutrients: [String: Nutrient] = [:] // Key is accessName ( - replaced with _ )
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
|
||||||
|
public subscript(dynamicMember member: String) -> Nutrient? {
|
||||||
|
nutrients[member]
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Decoding
|
||||||
|
public init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: AnyCodingKey.self)
|
||||||
|
for key in container.allKeys {
|
||||||
|
let keyStr = key.stringValue
|
||||||
|
let parts = keyStr.components(separatedBy: "_")
|
||||||
|
|
||||||
|
var nutrientName = "" // Original with -
|
||||||
|
var field = ""
|
||||||
|
var isPrepared = false
|
||||||
|
|
||||||
|
if let preparedIdx = parts.firstIndex(of: "prepared") {
|
||||||
|
isPrepared = true
|
||||||
|
nutrientName = parts[0..<preparedIdx].joined(separator: "_")
|
||||||
|
let afterParts = Array(parts[(preparedIdx + 1)...])
|
||||||
|
field = afterParts.joined(separator: "_")
|
||||||
|
} else {
|
||||||
|
nutrientName = parts.dropLast().joined(separator: "_")
|
||||||
|
field = parts.last ?? ""
|
||||||
|
}
|
||||||
|
|
||||||
|
let accessName = nutrientName.replacingOccurrences(
|
||||||
|
of: "-", with: "_")
|
||||||
|
if nutrients[accessName] == nil {
|
||||||
|
nutrients[accessName] = Nutrient(name: nutrientName)
|
||||||
|
}
|
||||||
|
|
||||||
|
let valDouble: Double? = try? container.decode(
|
||||||
|
Double.self, forKey: key)
|
||||||
|
let valString: String? = try? container.decode(
|
||||||
|
String.self, forKey: key)
|
||||||
|
|
||||||
|
let currentNutrient = nutrients[accessName]!
|
||||||
|
|
||||||
|
switch field {
|
||||||
|
case "":
|
||||||
|
if isPrepared {
|
||||||
|
currentNutrient.preparedValue = valDouble
|
||||||
|
} else {
|
||||||
|
currentNutrient.value = valDouble
|
||||||
|
}
|
||||||
|
case "value":
|
||||||
|
if isPrepared {
|
||||||
|
currentNutrient.preparedValueComputed = valDouble
|
||||||
|
} else {
|
||||||
|
currentNutrient.valueComputed = valDouble
|
||||||
|
}
|
||||||
|
case "100g":
|
||||||
|
if isPrepared {
|
||||||
|
currentNutrient.preparedPer100g = valDouble
|
||||||
|
} else {
|
||||||
|
currentNutrient.per100g = valDouble
|
||||||
|
}
|
||||||
|
case "serving":
|
||||||
|
if isPrepared {
|
||||||
|
currentNutrient.preparedPerServing = valDouble
|
||||||
|
} else {
|
||||||
|
currentNutrient.perServing = valDouble
|
||||||
|
}
|
||||||
|
case "unit":
|
||||||
|
if isPrepared {
|
||||||
|
currentNutrient.preparedUnit = valString
|
||||||
|
} else {
|
||||||
|
currentNutrient.unit = valString
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Skip unknown fields
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Encoding
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: AnyCodingKey.self)
|
||||||
|
for (_, nutrient) in nutrients {
|
||||||
|
// Base value
|
||||||
|
if let v = nutrient.value {
|
||||||
|
let key = AnyCodingKey(stringValue: nutrient.name)
|
||||||
|
try container.encode(v, forKey: key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _value
|
||||||
|
if let v = nutrient.valueComputed {
|
||||||
|
let key = AnyCodingKey(stringValue: "\(nutrient.name)_value")
|
||||||
|
try container.encode(v, forKey: key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _unit
|
||||||
|
if let u = nutrient.unit {
|
||||||
|
let key = AnyCodingKey(stringValue: "\(nutrient.name)_unit")
|
||||||
|
try container.encode(u, forKey: key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _100g
|
||||||
|
if let v = nutrient.per100g {
|
||||||
|
let key = AnyCodingKey(stringValue: "\(nutrient.name)_100g")
|
||||||
|
try container.encode(v, forKey: key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _serving
|
||||||
|
if let v = nutrient.perServing {
|
||||||
|
let key = AnyCodingKey(stringValue: "\(nutrient.name)_serving")
|
||||||
|
try container.encode(v, forKey: key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _prepared
|
||||||
|
if let v = nutrient.preparedValue {
|
||||||
|
let key = AnyCodingKey(stringValue: "\(nutrient.name)_prepared")
|
||||||
|
try container.encode(v, forKey: key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _prepared_value
|
||||||
|
if let v = nutrient.preparedValueComputed {
|
||||||
|
let key = AnyCodingKey(
|
||||||
|
stringValue: "\(nutrient.name)_prepared_value")
|
||||||
|
try container.encode(v, forKey: key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _prepared_unit
|
||||||
|
if let u = nutrient.preparedUnit {
|
||||||
|
let key = AnyCodingKey(
|
||||||
|
stringValue: "\(nutrient.name)_prepared_unit")
|
||||||
|
try container.encode(u, forKey: key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _prepared_100g
|
||||||
|
if let v = nutrient.preparedPer100g {
|
||||||
|
let key = AnyCodingKey(
|
||||||
|
stringValue: "\(nutrient.name)_prepared_100g")
|
||||||
|
try container.encode(v, forKey: key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _prepared_serving
|
||||||
|
if let v = nutrient.preparedPerServing {
|
||||||
|
let key = AnyCodingKey(
|
||||||
|
stringValue: "\(nutrient.name)_prepared_serving")
|
||||||
|
try container.encode(v, forKey: key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Nutrient Struct with Units Integration
|
||||||
|
public class Nutrient { // Class for mutability in decoding
|
||||||
|
public let name: String // Original name with -
|
||||||
|
|
||||||
|
public var value: Double?
|
||||||
|
public var valueComputed: Double?
|
||||||
|
public var per100g: Double?
|
||||||
|
public var perServing: Double?
|
||||||
|
public var unit: String?
|
||||||
|
|
||||||
|
public var preparedValue: Double?
|
||||||
|
public var preparedValueComputed: Double?
|
||||||
|
public var preparedPer100g: Double?
|
||||||
|
public var preparedPerServing: Double?
|
||||||
|
public var preparedUnit: String?
|
||||||
|
|
||||||
|
init(name: String) {
|
||||||
|
self.name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Integration with Units.swift
|
||||||
|
// Computed UnitValue for per100g (fallback to value or valueComputed if per100g is nil)
|
||||||
|
public var per100gUnitValue: UnitValue<Double>? {
|
||||||
|
guard let rawValue = per100g ?? value ?? valueComputed,
|
||||||
|
let unitString = unit,
|
||||||
|
let unitEnum = Unit(rawValue: unitString)
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return UnitValue(value: rawValue, unit: unitEnum)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computed UnitValue for perServing
|
||||||
|
public var perServingUnitValue: UnitValue<Double>? {
|
||||||
|
guard let rawValue = perServing,
|
||||||
|
let unitString = unit,
|
||||||
|
let unitEnum = Unit(rawValue: unitString)
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return UnitValue(value: rawValue, unit: unitEnum)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computed UnitValue for preparedPer100g (fallback similar)
|
||||||
|
public var preparedPer100gUnitValue: UnitValue<Double>? {
|
||||||
|
guard
|
||||||
|
let rawValue = preparedPer100g ?? preparedValue
|
||||||
|
?? preparedValueComputed,
|
||||||
|
let unitString = preparedUnit ?? unit, // Fallback to main unit if preparedUnit nil
|
||||||
|
let unitEnum = Unit(rawValue: unitString)
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return UnitValue(value: rawValue, unit: unitEnum)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computed UnitValue for preparedPerServing
|
||||||
|
public var preparedPerServingUnitValue: UnitValue<Double>? {
|
||||||
|
guard let rawValue = preparedPerServing,
|
||||||
|
let unitString = preparedUnit ?? unit,
|
||||||
|
let unitEnum = Unit(rawValue: unitString)
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return UnitValue(value: rawValue, unit: unitEnum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Helper for Dynamic Coding Keys
|
||||||
|
struct AnyCodingKey: CodingKey, Hashable {
|
||||||
|
var stringValue: String
|
||||||
|
var intValue: Int?
|
||||||
|
|
||||||
|
init(stringValue: String) {
|
||||||
|
self.stringValue = stringValue
|
||||||
|
self.intValue = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
init(intValue: Int) {
|
||||||
|
self.intValue = intValue
|
||||||
|
self.stringValue = String(intValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
58
Sources/OpenFoodFacts/Schemas/ObjectDebugger.swift
Normal file
58
Sources/OpenFoodFacts/Schemas/ObjectDebugger.swift
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
public protocol ObjectDebugger: CustomStringConvertible {
|
||||||
|
var description: String { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ObjectDebugger {
|
||||||
|
public var description: String {
|
||||||
|
var description = "\(type(of: self))("
|
||||||
|
let mirror = Mirror(reflecting: self)
|
||||||
|
|
||||||
|
for (label, value) in mirror.children {
|
||||||
|
if let label = label {
|
||||||
|
description += "\(label): \(value), "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the trailing comma and space
|
||||||
|
description = String(description.dropLast(2))
|
||||||
|
description += ")"
|
||||||
|
|
||||||
|
return description
|
||||||
|
}
|
||||||
|
|
||||||
|
private func prettyPrint(object: Any, indentation: String = "") -> String {
|
||||||
|
var description = "\(type(of: object)) {"
|
||||||
|
|
||||||
|
let mirror = Mirror(reflecting: object)
|
||||||
|
|
||||||
|
for (label, value) in mirror.children {
|
||||||
|
if let label = label {
|
||||||
|
let childDescription: String
|
||||||
|
switch value {
|
||||||
|
case let nestedObject as CustomStringConvertible:
|
||||||
|
childDescription = prettyPrint(
|
||||||
|
object: nestedObject, indentation: "\(indentation) ")
|
||||||
|
case let stringValue as String:
|
||||||
|
childDescription = "\"\(stringValue)\""
|
||||||
|
case let floatValue as Float:
|
||||||
|
childDescription = "\(floatValue)"
|
||||||
|
case let intValue as Int:
|
||||||
|
childDescription = "\(intValue)"
|
||||||
|
case let optionalValue as CustomStringConvertible?:
|
||||||
|
if let unwrapped = optionalValue {
|
||||||
|
childDescription = "\(unwrapped)"
|
||||||
|
} else {
|
||||||
|
childDescription = "nil"
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
childDescription = "\(value)"
|
||||||
|
}
|
||||||
|
|
||||||
|
description += "\n\(indentation) \(label): \(childDescription)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
description += "\n\(indentation)}"
|
||||||
|
return description
|
||||||
|
}
|
||||||
|
}
|
||||||
63
Sources/OpenFoodFacts/Schemas/PerlSearchQuery.swift
Normal file
63
Sources/OpenFoodFacts/Schemas/PerlSearchQuery.swift
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
public enum PerlOperator: String {
|
||||||
|
case lt, lte, gt, gte, eq
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PerlFormat: String {
|
||||||
|
case json, xml, jqm
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct SearchNutrimentEntry {
|
||||||
|
public let nutriment: SearchNutriment
|
||||||
|
public let op: PerlOperator
|
||||||
|
public let value: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct SearchTagsEntry {
|
||||||
|
public let tag: SearchTag
|
||||||
|
public let value: String
|
||||||
|
public let contains: Bool = true
|
||||||
|
}
|
||||||
|
|
||||||
|
//https://wiki.openfoodfacts.org/API/Read/Search#Parameters
|
||||||
|
public struct PerlSearchQuery {
|
||||||
|
public var searchTerms: String
|
||||||
|
public var searchTags: [SearchTagsEntry]? // tagtype_i=SearchTag — i as #element (starting from 0); (tag_contains_i|tag_does_not_contain_i)=String
|
||||||
|
public var searchNutriment: [SearchNutrimentEntry]? // nutriment_i=SearchNutriment — i as #element (starting from 0); nutriment_compare_i=PerlOperator; nutriment_value_i=String
|
||||||
|
public var page: Int = 1 // Pagination
|
||||||
|
public var format: PerlFormat // json=1 | xml=1 | jqm=1
|
||||||
|
|
||||||
|
public init(
|
||||||
|
searchTerms: String, searchTags: [SearchTagsEntry]? = nil,
|
||||||
|
searchNutriment: [SearchNutrimentEntry]? = nil, page: Int = 1,
|
||||||
|
format: PerlFormat = .json
|
||||||
|
) {
|
||||||
|
self.searchTerms = searchTerms
|
||||||
|
self.searchTags = searchTags
|
||||||
|
self.searchNutriment = searchNutriment
|
||||||
|
self.page = page
|
||||||
|
self.format = format
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeToRequest() -> String {
|
||||||
|
var _searchTags: String?
|
||||||
|
var _searchNutriment: String?
|
||||||
|
let _format: String = "\(format.rawValue)=1"
|
||||||
|
let _page: String = "page=\(page)"
|
||||||
|
if let tags = searchTags {
|
||||||
|
_searchTags = tags.enumerated().map { i, v in
|
||||||
|
return
|
||||||
|
"tagtype_\(i)=\(v.tag.rawValue)&tag_contains_\(i)=\(v.contains ? "contains" : "does_not_contain")&tag_\(i)=\(v.value)"
|
||||||
|
}.joined(separator: "&")
|
||||||
|
}
|
||||||
|
if let nutriments = searchNutriment {
|
||||||
|
_searchNutriment = nutriments.enumerated().map { i, v in
|
||||||
|
return
|
||||||
|
"nutriment_\(i)=\(v.nutriment.rawValue)&nutriment_compare_\(i)=\(v.op.rawValue)&nutriment_value_\(i)=\(v.nutriment.rawValue)"
|
||||||
|
}.joined(separator: "&")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
"search_terms=\(searchTerms)\(_searchTags != nil ? "&\(_searchTags!)" : "")\(_searchNutriment != nil ? "&\(_searchNutriment!)" : "")&\(_page)&\(_format)"
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
932
Sources/OpenFoodFacts/Schemas/Product.swift
Normal file
932
Sources/OpenFoodFacts/Schemas/Product.swift
Normal file
@@ -0,0 +1,932 @@
|
|||||||
|
public class Product: Codable, ObjectDebugger {
|
||||||
|
// public var images: Images? = Images()
|
||||||
|
public var ingredients: [Ingredient]? = []
|
||||||
|
public var languagesCodes: LanguagesCodes?
|
||||||
|
public var nutrientLevels: NutrientLevels?
|
||||||
|
public var nutriments: Nutriments? = Nutriments()
|
||||||
|
public var selectedImages: SelectedImages?
|
||||||
|
public var sources: [Source]? = []
|
||||||
|
public var additivesN: Float?
|
||||||
|
public var additivesOldN: Float?
|
||||||
|
public var additivesOriginalTags: [String]?
|
||||||
|
public var additivesOldTags: [String]?
|
||||||
|
public var additivesPrevOriginalTags: [String]?
|
||||||
|
public var additivesDebugTags: [String]?
|
||||||
|
public var additivesTags: [String]?
|
||||||
|
public var allergens: String?
|
||||||
|
public var allergensFromIngredients: String?
|
||||||
|
public var allergensFromUser: String?
|
||||||
|
public var allergensHierarchy: [String]?
|
||||||
|
public var allergensLc: String?
|
||||||
|
public var allergensTags: [String]?
|
||||||
|
public var aminoAcidsPrevTags: [String]?
|
||||||
|
public var aminoAcidsTags: [String]?
|
||||||
|
public var brands: String?
|
||||||
|
public var brandsDebugTags: [String]?
|
||||||
|
public var brandsTags: [String]?
|
||||||
|
public var carbonFootprintPercentOfKnownIngredients: Float?
|
||||||
|
public var carbonFootprintFromKnownIngredientsDebug: String?
|
||||||
|
public var categories: String?
|
||||||
|
public var categoriesHierarchy: [String]?
|
||||||
|
public var categoriesLc: String?
|
||||||
|
public var categoriesPropertiesTags: [String]?
|
||||||
|
public var categoriesTags: [String]?
|
||||||
|
public var checkersTags: [String]?
|
||||||
|
public var citiesTags: [String]?
|
||||||
|
public var code: String?
|
||||||
|
public var codesTags: [String]?
|
||||||
|
public var comparedToCategory: String?
|
||||||
|
public var complete: Float?
|
||||||
|
public var completedT: Float?
|
||||||
|
public var completeness: Double?
|
||||||
|
public var conservationConditions: String?
|
||||||
|
public var countries: String?
|
||||||
|
public var countriesHierarchy: [String]?
|
||||||
|
public var countriesLc: String?
|
||||||
|
public var countriesDebugTags: [String]?
|
||||||
|
public var countriesTags: [String]?
|
||||||
|
public var correctorsTags: [String]?
|
||||||
|
public var createdT: Float?
|
||||||
|
public var creator: String?
|
||||||
|
public var dataQualityBugsTags: [String]?
|
||||||
|
public var dataQualityErrorsTags: [String]?
|
||||||
|
public var dataQualityInfoTags: [String]?
|
||||||
|
public var dataQualityTags: [String]?
|
||||||
|
public var dataQualityWarningsTags: [String]?
|
||||||
|
public var dataSources: String?
|
||||||
|
public var dataSourcesTags: [String]?
|
||||||
|
public var debugParamSortedLangs: [String]?
|
||||||
|
public var editorsTags: [String]?
|
||||||
|
public var embCodes: String?
|
||||||
|
public var embCodesDebugTags: [String]?
|
||||||
|
public var embCodesOrig: String?
|
||||||
|
public var embCodesTags: [String]?
|
||||||
|
public var entryDatesTags: [String]?
|
||||||
|
public var expirationDate: String?
|
||||||
|
public var expirationDateDebugTags: [String]?
|
||||||
|
public var fruitsVegetablesNuts100GEstimate: Float?
|
||||||
|
public var genericName: String?
|
||||||
|
public var id: String?
|
||||||
|
public var imageFrontSmallUrl: String?
|
||||||
|
public var imageFrontThumbUrl: String?
|
||||||
|
public var imageFrontUrl: String?
|
||||||
|
public var imageIngredientsUrl: String?
|
||||||
|
public var imageIngredientsSmallUrl: String?
|
||||||
|
public var imageIngredientsThumbUrl: String?
|
||||||
|
public var imageNutritionSmallUrl: String?
|
||||||
|
public var imageNutritionThumbUrl: String?
|
||||||
|
public var imageNutritionUrl: String?
|
||||||
|
public var imageSmallUrl: String?
|
||||||
|
public var imageThumbUrl: String?
|
||||||
|
public var imageUrl: String?
|
||||||
|
public var informersTags: [String]?
|
||||||
|
public var ingredientsAnalysisTags: [String]?
|
||||||
|
public var ingredientsDebug: [String?]?
|
||||||
|
public var ingredientsFromOrThatMayBeFromPalmOilN: Float?
|
||||||
|
public var ingredientsFromPalmOilTags: [String]?
|
||||||
|
public var ingredientsFromPalmOilN: Float?
|
||||||
|
public var ingredientsHierarchy: [String]?
|
||||||
|
public var ingredientsIdsDebug: [String]?
|
||||||
|
public var ingredientsN: Float?
|
||||||
|
public var ingredientsNTags: [String]?
|
||||||
|
public var ingredientsOriginalTags: [String]?
|
||||||
|
public var ingredientsTags: [String]?
|
||||||
|
public var ingredientsText: String?
|
||||||
|
public var ingredientsTextDebug: String?
|
||||||
|
public var ingredientsTextWithAllergens: String?
|
||||||
|
public var ingredientsThatMayBeFromPalmOilN: Float?
|
||||||
|
public var ingredientsThatMayBeFromPalmOilTags: [String]?
|
||||||
|
public var interfaceVersionCreated: String?
|
||||||
|
public var interfaceVersionModified: String?
|
||||||
|
public var keywords: [String]?
|
||||||
|
public var knownIngredientsN: Float?
|
||||||
|
public var labels: String?
|
||||||
|
public var labelsHierarchy: [String]?
|
||||||
|
public var labelsLc: String?
|
||||||
|
public var labelsPrevHierarchy: [String]?
|
||||||
|
public var labelsPrevTags: [String]?
|
||||||
|
public var labelsTags: [String]?
|
||||||
|
public var labelsDebugTags: [String]?
|
||||||
|
public var lang: String?
|
||||||
|
public var langDebugTags: [String]?
|
||||||
|
public var languagesHierarchy: [String]?
|
||||||
|
public var languagesTags: [String]?
|
||||||
|
public var lastEditDatesTags: [String]?
|
||||||
|
public var lastEditor: String?
|
||||||
|
public var lastImageDatesTags: [String]?
|
||||||
|
public var lastImageT: Float?
|
||||||
|
public var lastModifiedBy: String?
|
||||||
|
public var lastModifiedT: Float?
|
||||||
|
public var lc: String?
|
||||||
|
public var link: String?
|
||||||
|
public var linkDebugTags: [String]?
|
||||||
|
public var manufacturingPlaces: String?
|
||||||
|
public var manufacturingPlacesDebugTags: [String]?
|
||||||
|
public var manufacturingPlacesTags: [String]?
|
||||||
|
public var maxImgid: String?
|
||||||
|
public var mineralsPrevTags: [String]?
|
||||||
|
public var mineralsTags: [String]?
|
||||||
|
public var miscTags: [String]?
|
||||||
|
public var netWeightUnit: String?
|
||||||
|
public var netWeightValue: String?
|
||||||
|
public var nutritionDataPer: String?
|
||||||
|
public var nutritionScoreWarningNoFruitsVegetablesNuts: Float?
|
||||||
|
public var nutriscoreGrade: String?
|
||||||
|
public var noNutritionData: String?
|
||||||
|
public var novaGroup: Float?
|
||||||
|
public var novaGroups: String?
|
||||||
|
public var novaGroupDebug: String?
|
||||||
|
public var novaGroupTags: [String]?
|
||||||
|
public var novaGroupsTags: [String]?
|
||||||
|
public var nucleotidesPrevTags: [String]?
|
||||||
|
public var nucleotidesTags: [String]?
|
||||||
|
public var nutrientLevelsTags: [String]?
|
||||||
|
public var nutritionData: String?
|
||||||
|
public var nutritionDataPerDebugTags: [String]?
|
||||||
|
public var nutritionDataPrepared: String?
|
||||||
|
public var nutritionDataPreparedPer: String?
|
||||||
|
public var nutritionGrades: String?
|
||||||
|
public var nutritionScoreBeverage: Float?
|
||||||
|
public var nutritionScoreDebug: String?
|
||||||
|
public var nutritionScoreWarningNoFiber: Float?
|
||||||
|
public var nutritionGradesTags: [String]?
|
||||||
|
public var origins: String?
|
||||||
|
public var originsDebugTags: [String]?
|
||||||
|
public var originsTags: [String]?
|
||||||
|
public var otherInformation: String?
|
||||||
|
public var otherNutritionalSubstancesTags: [String]?
|
||||||
|
public var packaging: String?
|
||||||
|
public var packagingDebugTags: [String]?
|
||||||
|
public var packagingTags: [String]?
|
||||||
|
public var photographersTags: [String]?
|
||||||
|
public var pnnsGroups1: String?
|
||||||
|
public var pnnsGroups2: String?
|
||||||
|
public var pnnsGroups1Tags: [String]?
|
||||||
|
public var pnnsGroups2Tags: [String]?
|
||||||
|
public var popularityKey: Float?
|
||||||
|
public var producerVersionId: String?
|
||||||
|
public var productName: String?
|
||||||
|
public var productQuantity: Float?
|
||||||
|
public var purchasePlaces: String?
|
||||||
|
public var purchasePlacesDebugTags: [String]?
|
||||||
|
public var purchasePlacesTags: [String]?
|
||||||
|
public var qualityTags: [String]?
|
||||||
|
public var quantity: String?
|
||||||
|
public var quantityDebugTags: [String]?
|
||||||
|
public var recyclingInstructionsToDiscard: String?
|
||||||
|
public var rev: Float?
|
||||||
|
public var servingQuantity: String?
|
||||||
|
public var servingSize: String?
|
||||||
|
public var servingSizeDebugTags: [String]?
|
||||||
|
public var sortkey: Float?
|
||||||
|
public var states: String?
|
||||||
|
public var statesHierarchy: [String]?
|
||||||
|
public var statesTags: [String]?
|
||||||
|
public var stores: String?
|
||||||
|
public var storesDebugTags: [String]?
|
||||||
|
public var storesTags: [String]?
|
||||||
|
public var traces: String?
|
||||||
|
public var tracesFromIngredients: String?
|
||||||
|
public var tracesHierarchy: [String]?
|
||||||
|
public var tracesDebugTags: [String]?
|
||||||
|
public var tracesFromUser: String?
|
||||||
|
public var tracesLc: String?
|
||||||
|
public var tracesTags: [String]?
|
||||||
|
public var unknownIngredientsN: Float?
|
||||||
|
public var unknownNutrientsTags: [String]?
|
||||||
|
public var updateKey: String?
|
||||||
|
public var vitaminsPrevTags: [String]?
|
||||||
|
public var vitaminsTags: [String]?
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
// case images
|
||||||
|
case ingredients
|
||||||
|
case languagesCodes = "languages_codes"
|
||||||
|
case nutrientLevels = "nutrient_levels"
|
||||||
|
case nutriments
|
||||||
|
case selectedImages = "selected_images"
|
||||||
|
case sources
|
||||||
|
case additivesN = "additives_n"
|
||||||
|
case additivesOldN = "additives_old_n"
|
||||||
|
case additivesOriginalTags = "additives_original_tags"
|
||||||
|
case additivesOldTags = "additives_old_tags"
|
||||||
|
case additivesPrevOriginalTags = "additives_prev_original_tags"
|
||||||
|
case additivesDebugTags = "additives_debug_tags"
|
||||||
|
case additivesTags = "additives_tags"
|
||||||
|
case allergens
|
||||||
|
case allergensFromIngredients = "allergens_from_ingredients"
|
||||||
|
case allergensFromUser = "allergens_from_user"
|
||||||
|
case allergensHierarchy = "allergens_hierarchy"
|
||||||
|
case allergensLc = "allergens_lc"
|
||||||
|
case allergensTags = "allergens_tags"
|
||||||
|
case aminoAcidsPrevTags = "amino_acids_prev_tags"
|
||||||
|
case aminoAcidsTags = "amino_acids_tags"
|
||||||
|
case brands
|
||||||
|
case brandsDebugTags = "brands_debug_tags"
|
||||||
|
case brandsTags = "brands_tags"
|
||||||
|
case carbonFootprintPercentOfKnownIngredients =
|
||||||
|
"carbon_footprint_percent_of_known_ingredients"
|
||||||
|
case carbonFootprintFromKnownIngredientsDebug =
|
||||||
|
"carbon_footprint_from_known_ingredients_debug"
|
||||||
|
case categories
|
||||||
|
case categoriesHierarchy = "categories_hierarchy"
|
||||||
|
case categoriesLc = "categories_lc"
|
||||||
|
case categoriesPropertiesTags = "categories_properties_tags"
|
||||||
|
case categoriesTags = "categories_tags"
|
||||||
|
case checkersTags = "checkers_tags"
|
||||||
|
case citiesTags = "cities_tags"
|
||||||
|
case code
|
||||||
|
case codesTags = "codes_tags"
|
||||||
|
case comparedToCategory = "compared_to_category"
|
||||||
|
case complete
|
||||||
|
case completedT = "completed_t"
|
||||||
|
case completeness
|
||||||
|
case conservationConditions = "conservation_conditions"
|
||||||
|
case countries
|
||||||
|
case countriesHierarchy = "countries_hierarchy"
|
||||||
|
case countriesLc = "countries_lc"
|
||||||
|
case countriesDebugTags = "countries_debug_tags"
|
||||||
|
case countriesTags = "countries_tags"
|
||||||
|
case correctorsTags = "correctors_tags"
|
||||||
|
case createdT = "created_t"
|
||||||
|
case creator
|
||||||
|
case dataQualityBugsTags = "data_quality_bugs_tags"
|
||||||
|
case dataQualityErrorsTags = "data_quality_errors_tags"
|
||||||
|
case dataQualityInfoTags = "data_quality_info_tags"
|
||||||
|
case dataQualityTags = "data_quality_tags"
|
||||||
|
case dataQualityWarningsTags = "data_quality_warnings_tags"
|
||||||
|
case dataSources = "data_sources"
|
||||||
|
case dataSourcesTags = "data_sources_tags"
|
||||||
|
case debugParamSortedLangs = "debug_param_sorted_langs"
|
||||||
|
case editorsTags = "editors_tags"
|
||||||
|
case embCodes = "emb_codes"
|
||||||
|
case embCodesDebugTags = "emb_codes_debug_tags"
|
||||||
|
case embCodesOrig = "emb_codes_orig"
|
||||||
|
case embCodesTags = "emb_codes_tags"
|
||||||
|
case entryDatesTags = "entry_dates_tags"
|
||||||
|
case expirationDate = "expiration_date"
|
||||||
|
case expirationDateDebugTags = "expiration_date_debug_tags"
|
||||||
|
case fruitsVegetablesNuts100GEstimate =
|
||||||
|
"fruits-vegetables-nuts_100g_estimate"
|
||||||
|
case genericName
|
||||||
|
case id
|
||||||
|
case imageFrontSmallUrl = "image_front_small_url"
|
||||||
|
case imageFrontThumbUrl = "image_front_thumb_url"
|
||||||
|
case imageFrontUrl = "image_front_url"
|
||||||
|
case imageIngredientsUrl = "image_ingredients_url"
|
||||||
|
case imageIngredientsSmallUrl = "image_ingredients_small_url"
|
||||||
|
case imageIngredientsThumbUrl = "image_ingredients_thumb_url"
|
||||||
|
case imageNutritionSmallUrl = "image_nutrition_small_url"
|
||||||
|
case imageNutritionThumbUrl = "image_nutrition_thumb_url"
|
||||||
|
case imageNutritionUrl = "image_nutrition_url"
|
||||||
|
case imageSmallUrl = "image_small_url"
|
||||||
|
case imageThumbUrl = "image_thumb_url"
|
||||||
|
case imageUrl = "image_url"
|
||||||
|
case informersTags = "informers_tags"
|
||||||
|
case ingredientsAnalysisTags = "ingredients_analysis_tags"
|
||||||
|
case ingredientsDebug = "ingredients_debug"
|
||||||
|
case ingredientsFromOrThatMayBeFromPalmOilN =
|
||||||
|
"ingredients_from_or_that_may_be_from_palm_oil_n"
|
||||||
|
case ingredientsFromPalmOilTags = "ingredients_from_palm_oil_tags"
|
||||||
|
case ingredientsFromPalmOilN = "ingredients_from_palm_oil_n"
|
||||||
|
case ingredientsHierarchy = "ingredients_hierarchy"
|
||||||
|
case ingredientsIdsDebug = "ingredients_ids_debug"
|
||||||
|
case ingredientsN = "ingredients_n"
|
||||||
|
case ingredientsNTags = "ingredients_n_tags"
|
||||||
|
case ingredientsOriginalTags = "ingredients_original_tags"
|
||||||
|
case ingredientsTags = "ingredients_tags"
|
||||||
|
case ingredientsText = "ingredients_text"
|
||||||
|
case ingredientsTextDebug = "ingredients_text_debug"
|
||||||
|
case ingredientsTextWithAllergens = "ingredients_text_with_allergens"
|
||||||
|
case ingredientsThatMayBeFromPalmOilN =
|
||||||
|
"ingredients_that_may_be_from_palm_oil_n"
|
||||||
|
case ingredientsThatMayBeFromPalmOilTags =
|
||||||
|
"ingredients_that_may_be_from_palm_oil_tags"
|
||||||
|
case interfaceVersionCreated = "interface_version_created"
|
||||||
|
case interfaceVersionModified = "interface_version_modified"
|
||||||
|
case keywords
|
||||||
|
case knownIngredientsN = "known_ingredients_n"
|
||||||
|
case labels
|
||||||
|
case labelsHierarchy = "labels_hierarchy"
|
||||||
|
case labelsLc = "labels_lc"
|
||||||
|
case labelsPrevHierarchy = "labels_prev_hierarchy"
|
||||||
|
case labelsPrevTags = "labels_prev_tags"
|
||||||
|
case labelsTags = "labels_tags"
|
||||||
|
case labelsDebugTags = "labels_debug_tags"
|
||||||
|
case lang
|
||||||
|
case langDebugTags = "lang_debug_tags"
|
||||||
|
case languagesHierarchy = "languages_hierarchy"
|
||||||
|
case languagesTags = "languages_tags"
|
||||||
|
case lastEditDatesTags = "last_edit_dates_tags"
|
||||||
|
case lastEditor = "last_editor"
|
||||||
|
case lastImageDatesTags = "last_image_dates_tags"
|
||||||
|
case lastImageT = "last_image_t"
|
||||||
|
case lastModifiedBy = "last_modified_by"
|
||||||
|
case lastModifiedT = "last_modified_t"
|
||||||
|
case lc
|
||||||
|
case link
|
||||||
|
case linkDebugTags = "link_debug_tags"
|
||||||
|
case manufacturingPlaces = "manufacturing_places"
|
||||||
|
case manufacturingPlacesDebugTags = "manufacturing_places_debug_tags"
|
||||||
|
case manufacturingPlacesTags = "manufacturing_places_tags"
|
||||||
|
case maxImgid = "max_imgid"
|
||||||
|
case mineralsPrevTags = "minerals_prev_tags"
|
||||||
|
case mineralsTags = "minerals_tags"
|
||||||
|
case miscTags = "misc_tags"
|
||||||
|
case netWeightUnit = "net_weight_unit"
|
||||||
|
case netWeightValue = "net_weight_value"
|
||||||
|
case nutritionDataPer = "nutrition_data_per"
|
||||||
|
case nutritionScoreWarningNoFruitsVegetablesNuts =
|
||||||
|
"nutrition_score_warning_no_fruits_vegetables_nuts"
|
||||||
|
case nutriscoreGrade = "nutriscore_grade"
|
||||||
|
case noNutritionData = "no_nutrition_data"
|
||||||
|
case novaGroup = "nova_group"
|
||||||
|
case novaGroups = "nova_groups"
|
||||||
|
case novaGroupDebug = "nova_group_debug"
|
||||||
|
case novaGroupTags = "nova_group_tags"
|
||||||
|
case novaGroupsTags = "nova_groups_tags"
|
||||||
|
case nucleotidesPrevTags = "nucleotides_prev_tags"
|
||||||
|
case nucleotidesTags = "nucleotides_tags"
|
||||||
|
case nutrientLevelsTags = "nutrient_levels_tags"
|
||||||
|
case nutritionData = "nutrition_data"
|
||||||
|
case nutritionDataPerDebugTags = "nutrition_data_per_debug_tags"
|
||||||
|
case nutritionDataPrepared = "nutrition_data_prepared"
|
||||||
|
case nutritionDataPreparedPer = "nutrition_data_prepared_per"
|
||||||
|
case nutritionGrades = "nutrition_grades"
|
||||||
|
case nutritionScoreBeverage = "nutrition_score_beverage"
|
||||||
|
case nutritionScoreDebug = "nutrition_score_debug"
|
||||||
|
case nutritionScoreWarningNoFiber = "nutrition_score_warning_no_fiber"
|
||||||
|
case nutritionGradesTags = "nutrition_grades_tags"
|
||||||
|
case origins
|
||||||
|
case originsDebugTags = "origins_debug_tags"
|
||||||
|
case originsTags = "origins_tags"
|
||||||
|
case otherInformation = "other_information"
|
||||||
|
case otherNutritionalSubstancesTags =
|
||||||
|
"other_nutritional_substances_tags"
|
||||||
|
case packaging
|
||||||
|
case packagingDebugTags = "packaging_debug_tags"
|
||||||
|
case packagingTags = "packaging_tags"
|
||||||
|
case photographersTags = "photographers_tags"
|
||||||
|
case pnnsGroups1 = "pnns_groups_1"
|
||||||
|
case pnnsGroups2 = "pnns_groups_2"
|
||||||
|
case pnnsGroups1Tags = "pnns_groups_1_tags"
|
||||||
|
case pnnsGroups2Tags = "pnns_groups_2_tags"
|
||||||
|
case popularityKey = "popularity_key"
|
||||||
|
case producerVersionId = "producer_version_id"
|
||||||
|
case productName = "product_name"
|
||||||
|
case productQuantity = "product_quantity"
|
||||||
|
case purchasePlaces = "purchase_places"
|
||||||
|
case purchasePlacesDebugTags = "purchase_places_debug_tags"
|
||||||
|
case purchasePlacesTags = "purchase_places_tags"
|
||||||
|
case qualityTags = "quality_tags"
|
||||||
|
case quantity
|
||||||
|
case quantityDebugTags = "quantity_debug_tags"
|
||||||
|
case recyclingInstructionsToDiscard =
|
||||||
|
"recycling_instructions_to_discard"
|
||||||
|
case rev
|
||||||
|
case servingQuantity = "serving_quantity"
|
||||||
|
case servingSize = "serving_size"
|
||||||
|
case servingSizeDebugTags = "serving_size_debug_tags"
|
||||||
|
case sortkey
|
||||||
|
case states
|
||||||
|
case statesHierarchy = "states_hierarchy"
|
||||||
|
case statesTags = "states_tags"
|
||||||
|
case stores
|
||||||
|
case storesDebugTags = "stores_debug_tags"
|
||||||
|
case storesTags = "stores_tags"
|
||||||
|
case traces
|
||||||
|
case tracesFromIngredients = "traces_from_ingredients"
|
||||||
|
case tracesHierarchy = "traces_hierarchy"
|
||||||
|
case tracesDebugTags = "traces_debug_tags"
|
||||||
|
case tracesFromUser = "traces_from_user"
|
||||||
|
case tracesLc = "traces_lc"
|
||||||
|
case tracesTags = "traces_tags"
|
||||||
|
case unknownIngredientsN = "unknown_ingredients_n"
|
||||||
|
case unknownNutrientsTags = "unknown_nutrients_tags"
|
||||||
|
case updateKey = "update_key"
|
||||||
|
case vitaminsPrevTags = "vitamins_prev_tags"
|
||||||
|
case vitaminsTags = "vitamins_tags"
|
||||||
|
}
|
||||||
|
|
||||||
|
public required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
ingredients = try container.decodeIfPresent(
|
||||||
|
[Ingredient].self, forKey: .ingredients)
|
||||||
|
languagesCodes = try container.decodeIfPresent(
|
||||||
|
LanguagesCodes.self, forKey: .languagesCodes)
|
||||||
|
nutrientLevels = try container.decodeIfPresent(
|
||||||
|
NutrientLevels.self, forKey: .nutrientLevels)
|
||||||
|
nutriments =
|
||||||
|
try container.decodeIfPresent(Nutriments.self, forKey: .nutriments)
|
||||||
|
?? Nutriments()
|
||||||
|
selectedImages = try container.decodeIfPresent(
|
||||||
|
SelectedImages.self, forKey: .selectedImages)
|
||||||
|
sources = try container.decodeIfPresent([Source].self, forKey: .sources)
|
||||||
|
additivesN = try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .additivesN)
|
||||||
|
additivesOldN = try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .additivesOldN)
|
||||||
|
additivesOriginalTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .additivesOriginalTags)
|
||||||
|
additivesOldTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .additivesOldTags)
|
||||||
|
additivesPrevOriginalTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .additivesPrevOriginalTags)
|
||||||
|
additivesDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .additivesDebugTags)
|
||||||
|
additivesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .additivesTags)
|
||||||
|
allergens = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .allergens)
|
||||||
|
allergensFromIngredients = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .allergensFromIngredients)
|
||||||
|
allergensFromUser = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .allergensFromUser)
|
||||||
|
allergensHierarchy = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .allergensHierarchy)
|
||||||
|
allergensLc = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .allergensLc)
|
||||||
|
allergensTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .allergensTags)
|
||||||
|
aminoAcidsPrevTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .aminoAcidsPrevTags)
|
||||||
|
aminoAcidsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .aminoAcidsTags)
|
||||||
|
brands = try container.decodeIfPresent(String.self, forKey: .brands)
|
||||||
|
brandsDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .brandsDebugTags)
|
||||||
|
brandsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .brandsTags)
|
||||||
|
carbonFootprintPercentOfKnownIngredients =
|
||||||
|
try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .carbonFootprintPercentOfKnownIngredients)
|
||||||
|
carbonFootprintFromKnownIngredientsDebug =
|
||||||
|
try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .carbonFootprintFromKnownIngredientsDebug)
|
||||||
|
categories = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .categories)
|
||||||
|
categoriesHierarchy = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .categoriesHierarchy)
|
||||||
|
categoriesLc = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .categoriesLc)
|
||||||
|
categoriesPropertiesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .categoriesPropertiesTags)
|
||||||
|
categoriesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .categoriesTags)
|
||||||
|
checkersTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .checkersTags)
|
||||||
|
citiesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .citiesTags)
|
||||||
|
code = try container.decodeIfPresent(String.self, forKey: .code)
|
||||||
|
codesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .codesTags)
|
||||||
|
comparedToCategory = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .comparedToCategory)
|
||||||
|
complete = try container.decodeIfPresent(Float.self, forKey: .complete)
|
||||||
|
completedT = try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .completedT)
|
||||||
|
completeness = try container.decodeIfPresent(
|
||||||
|
Double.self, forKey: .completeness)
|
||||||
|
conservationConditions = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .conservationConditions)
|
||||||
|
countries = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .countries)
|
||||||
|
countriesHierarchy = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .countriesHierarchy)
|
||||||
|
countriesLc = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .countriesLc)
|
||||||
|
countriesDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .countriesDebugTags)
|
||||||
|
countriesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .countriesTags)
|
||||||
|
correctorsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .correctorsTags)
|
||||||
|
createdT = try container.decodeIfPresent(Float.self, forKey: .createdT)
|
||||||
|
creator = try container.decodeIfPresent(String.self, forKey: .creator)
|
||||||
|
dataQualityBugsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .dataQualityBugsTags)
|
||||||
|
dataQualityErrorsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .dataQualityErrorsTags)
|
||||||
|
dataQualityInfoTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .dataQualityInfoTags)
|
||||||
|
dataQualityTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .dataQualityTags)
|
||||||
|
dataQualityWarningsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .dataQualityWarningsTags)
|
||||||
|
dataSources = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .dataSources)
|
||||||
|
dataSourcesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .dataSourcesTags)
|
||||||
|
debugParamSortedLangs = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .debugParamSortedLangs)
|
||||||
|
editorsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .editorsTags)
|
||||||
|
embCodes = try container.decodeIfPresent(String.self, forKey: .embCodes)
|
||||||
|
embCodesDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .embCodesDebugTags)
|
||||||
|
embCodesOrig = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .embCodesOrig)
|
||||||
|
embCodesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .embCodesTags)
|
||||||
|
entryDatesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .entryDatesTags)
|
||||||
|
expirationDate = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .expirationDate)
|
||||||
|
expirationDateDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .expirationDateDebugTags)
|
||||||
|
fruitsVegetablesNuts100GEstimate = try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .fruitsVegetablesNuts100GEstimate)
|
||||||
|
genericName = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .genericName)
|
||||||
|
id = try container.decodeIfPresent(String.self, forKey: .id)
|
||||||
|
imageFrontSmallUrl = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .imageFrontSmallUrl)
|
||||||
|
imageFrontThumbUrl = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .imageFrontThumbUrl)
|
||||||
|
imageFrontUrl = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .imageFrontUrl)
|
||||||
|
imageIngredientsUrl = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .imageIngredientsUrl)
|
||||||
|
imageIngredientsSmallUrl = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .imageIngredientsSmallUrl)
|
||||||
|
imageIngredientsThumbUrl = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .imageIngredientsThumbUrl)
|
||||||
|
imageNutritionSmallUrl = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .imageNutritionSmallUrl)
|
||||||
|
imageNutritionThumbUrl = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .imageNutritionThumbUrl)
|
||||||
|
imageNutritionUrl = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .imageNutritionUrl)
|
||||||
|
imageSmallUrl = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .imageSmallUrl)
|
||||||
|
imageThumbUrl = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .imageThumbUrl)
|
||||||
|
imageUrl = try container.decodeIfPresent(String.self, forKey: .imageUrl)
|
||||||
|
informersTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .informersTags)
|
||||||
|
ingredientsAnalysisTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .ingredientsAnalysisTags)
|
||||||
|
ingredientsDebug = try container.decodeIfPresent(
|
||||||
|
[String?].self, forKey: .ingredientsDebug)
|
||||||
|
ingredientsFromOrThatMayBeFromPalmOilN = try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .ingredientsFromOrThatMayBeFromPalmOilN)
|
||||||
|
ingredientsFromPalmOilTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .ingredientsFromPalmOilTags)
|
||||||
|
ingredientsFromPalmOilN = try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .ingredientsFromPalmOilN)
|
||||||
|
ingredientsHierarchy = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .ingredientsHierarchy)
|
||||||
|
ingredientsIdsDebug = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .ingredientsIdsDebug)
|
||||||
|
if container.contains(.ingredientsN) {
|
||||||
|
if try container.decodeNil(forKey: .ingredientsN) {
|
||||||
|
ingredientsN = nil
|
||||||
|
} else {
|
||||||
|
if let intValue = try? container.decode(
|
||||||
|
Float.self, forKey: .ingredientsN)
|
||||||
|
{
|
||||||
|
ingredientsN = intValue
|
||||||
|
} else if let stringValue = try? container.decode(
|
||||||
|
String.self, forKey: .ingredientsN)
|
||||||
|
{
|
||||||
|
ingredientsN = Float(stringValue)
|
||||||
|
} else {
|
||||||
|
// If decoding as both Float and String fails, handle the error accordingly
|
||||||
|
throw DecodingError.dataCorruptedError(
|
||||||
|
forKey: .ingredientsN,
|
||||||
|
in: container,
|
||||||
|
debugDescription: "Unable to decode ingredientsN"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ingredientsN = nil
|
||||||
|
}
|
||||||
|
ingredientsNTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .ingredientsNTags)
|
||||||
|
ingredientsOriginalTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .ingredientsOriginalTags)
|
||||||
|
ingredientsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .ingredientsTags)
|
||||||
|
ingredientsText = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .ingredientsText)
|
||||||
|
ingredientsTextDebug = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .ingredientsTextDebug)
|
||||||
|
ingredientsTextWithAllergens = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .ingredientsTextWithAllergens)
|
||||||
|
ingredientsThatMayBeFromPalmOilN = try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .ingredientsThatMayBeFromPalmOilN)
|
||||||
|
ingredientsThatMayBeFromPalmOilTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .ingredientsThatMayBeFromPalmOilTags)
|
||||||
|
interfaceVersionCreated = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .interfaceVersionCreated)
|
||||||
|
interfaceVersionModified = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .interfaceVersionModified)
|
||||||
|
keywords = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .keywords)
|
||||||
|
knownIngredientsN = try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .knownIngredientsN)
|
||||||
|
labels = try container.decodeIfPresent(String.self, forKey: .labels)
|
||||||
|
labelsHierarchy = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .labelsHierarchy)
|
||||||
|
labelsLc = try container.decodeIfPresent(String.self, forKey: .labelsLc)
|
||||||
|
labelsPrevHierarchy = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .labelsPrevHierarchy)
|
||||||
|
labelsPrevTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .labelsPrevTags)
|
||||||
|
labelsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .labelsTags)
|
||||||
|
labelsDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .labelsDebugTags)
|
||||||
|
lang = try container.decodeIfPresent(String.self, forKey: .lang)
|
||||||
|
langDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .langDebugTags)
|
||||||
|
languagesHierarchy = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .languagesHierarchy)
|
||||||
|
languagesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .languagesTags)
|
||||||
|
lastEditDatesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .lastEditDatesTags)
|
||||||
|
lastEditor = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .lastEditor)
|
||||||
|
lastImageDatesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .lastImageDatesTags)
|
||||||
|
lastImageT = try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .lastImageT)
|
||||||
|
lastModifiedBy = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .lastModifiedBy)
|
||||||
|
if container.contains(.lastModifiedT) {
|
||||||
|
if try container.decodeNil(forKey: .maxImgid) {
|
||||||
|
lastModifiedT = nil
|
||||||
|
} else {
|
||||||
|
if let floatValue = try? container.decode(
|
||||||
|
Float.self, forKey: .lastModifiedT)
|
||||||
|
{
|
||||||
|
lastModifiedT = floatValue
|
||||||
|
} else if let stringValue = try? container.decode(
|
||||||
|
String.self, forKey: .lastModifiedT)
|
||||||
|
{
|
||||||
|
lastModifiedT = Float(stringValue)
|
||||||
|
} else {
|
||||||
|
// If decoding as both Float and String fails, handle the error accordingly
|
||||||
|
throw DecodingError.dataCorruptedError(
|
||||||
|
forKey: .lastModifiedT,
|
||||||
|
in: container,
|
||||||
|
debugDescription: "Unable to decode lastModifiedT"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lastModifiedT = nil
|
||||||
|
}
|
||||||
|
lc = try container.decodeIfPresent(String.self, forKey: .lc)
|
||||||
|
link = try container.decodeIfPresent(String.self, forKey: .link)
|
||||||
|
linkDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .linkDebugTags)
|
||||||
|
manufacturingPlaces = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .manufacturingPlaces)
|
||||||
|
manufacturingPlacesDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .manufacturingPlacesDebugTags)
|
||||||
|
manufacturingPlacesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .manufacturingPlacesTags)
|
||||||
|
if container.contains(.maxImgid) {
|
||||||
|
if try container.decodeNil(forKey: .maxImgid) {
|
||||||
|
maxImgid = nil
|
||||||
|
} else {
|
||||||
|
if let floatValue = try? container.decode(
|
||||||
|
Float.self, forKey: .maxImgid)
|
||||||
|
{
|
||||||
|
maxImgid = "\(floatValue)"
|
||||||
|
} else if let stringValue = try? container.decode(
|
||||||
|
String.self, forKey: .maxImgid)
|
||||||
|
{
|
||||||
|
maxImgid = stringValue
|
||||||
|
} else {
|
||||||
|
// If decoding as both Float and String fails, handle the error accordingly
|
||||||
|
throw DecodingError.dataCorruptedError(
|
||||||
|
forKey: .maxImgid,
|
||||||
|
in: container,
|
||||||
|
debugDescription: "Unable to decode maxImgid"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
maxImgid = nil
|
||||||
|
}
|
||||||
|
mineralsPrevTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .mineralsPrevTags)
|
||||||
|
mineralsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .mineralsTags)
|
||||||
|
miscTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .miscTags)
|
||||||
|
netWeightUnit = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .netWeightUnit)
|
||||||
|
netWeightValue = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .netWeightValue)
|
||||||
|
nutritionDataPer = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .nutritionDataPer)
|
||||||
|
nutritionScoreWarningNoFruitsVegetablesNuts =
|
||||||
|
try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .nutritionScoreWarningNoFruitsVegetablesNuts
|
||||||
|
)
|
||||||
|
noNutritionData = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .noNutritionData)
|
||||||
|
novaGroup = try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .novaGroup)
|
||||||
|
novaGroups = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .novaGroups)
|
||||||
|
novaGroupDebug = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .novaGroupDebug)
|
||||||
|
novaGroupTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .novaGroupTags)
|
||||||
|
novaGroupsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .novaGroupsTags)
|
||||||
|
nucleotidesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .nucleotidesTags)
|
||||||
|
nutrientLevelsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .nutrientLevelsTags)
|
||||||
|
nutritionData = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .nutritionData)
|
||||||
|
nutriscoreGrade = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .nutriscoreGrade)
|
||||||
|
nutritionDataPerDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .nutritionDataPerDebugTags)
|
||||||
|
nutritionDataPrepared = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .nutritionDataPrepared)
|
||||||
|
nutritionDataPreparedPer = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .nutritionDataPreparedPer)
|
||||||
|
nutritionGrades = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .nutritionGrades)
|
||||||
|
nutritionScoreBeverage = try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .nutritionScoreBeverage)
|
||||||
|
nutritionScoreDebug = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .nutritionScoreDebug)
|
||||||
|
nutritionScoreWarningNoFiber = try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .nutritionScoreWarningNoFiber)
|
||||||
|
nutritionGradesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .nutritionGradesTags)
|
||||||
|
origins = try container.decodeIfPresent(String.self, forKey: .origins)
|
||||||
|
originsDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .originsDebugTags)
|
||||||
|
originsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .originsTags)
|
||||||
|
otherInformation = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .otherInformation)
|
||||||
|
otherNutritionalSubstancesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .otherNutritionalSubstancesTags)
|
||||||
|
packaging = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .packaging)
|
||||||
|
packagingDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .packagingDebugTags)
|
||||||
|
packagingTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .packagingTags)
|
||||||
|
photographersTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .photographersTags)
|
||||||
|
pnnsGroups1 = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .pnnsGroups1)
|
||||||
|
pnnsGroups2 = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .pnnsGroups2)
|
||||||
|
pnnsGroups1Tags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .pnnsGroups1Tags)
|
||||||
|
pnnsGroups2Tags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .pnnsGroups2Tags)
|
||||||
|
popularityKey = try container.decodeIfPresent(
|
||||||
|
Float.self, forKey: .popularityKey)
|
||||||
|
producerVersionId = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .producerVersionId)
|
||||||
|
productName = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .productName)
|
||||||
|
purchasePlaces = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .purchasePlaces)
|
||||||
|
purchasePlacesDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .purchasePlacesDebugTags)
|
||||||
|
purchasePlacesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .purchasePlacesTags)
|
||||||
|
qualityTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .qualityTags)
|
||||||
|
quantity = try container.decodeIfPresent(String.self, forKey: .quantity)
|
||||||
|
quantityDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .quantityDebugTags)
|
||||||
|
recyclingInstructionsToDiscard = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .recyclingInstructionsToDiscard)
|
||||||
|
rev = try container.decodeIfPresent(Float.self, forKey: .rev)
|
||||||
|
if container.contains(.servingQuantity) {
|
||||||
|
if try container.decodeNil(forKey: .servingQuantity) {
|
||||||
|
servingQuantity = nil
|
||||||
|
} else {
|
||||||
|
if let floatValue = try? container.decode(
|
||||||
|
Float.self, forKey: .servingQuantity)
|
||||||
|
{
|
||||||
|
servingQuantity = "\(floatValue)"
|
||||||
|
} else if let stringValue = try? container.decode(
|
||||||
|
String.self, forKey: .servingQuantity)
|
||||||
|
{
|
||||||
|
servingQuantity = stringValue
|
||||||
|
} else {
|
||||||
|
// If decoding as both Float and String fails, handle the error accordingly
|
||||||
|
throw DecodingError.dataCorruptedError(
|
||||||
|
forKey: .servingQuantity,
|
||||||
|
in: container,
|
||||||
|
debugDescription: "Unable to decode servingQuantity"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
servingQuantity = nil
|
||||||
|
}
|
||||||
|
servingSize = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .servingSize)
|
||||||
|
servingSizeDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .servingSizeDebugTags)
|
||||||
|
sortkey = try container.decodeIfPresent(Float.self, forKey: .sortkey)
|
||||||
|
states = try container.decodeIfPresent(String.self, forKey: .states)
|
||||||
|
statesHierarchy = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .statesHierarchy)
|
||||||
|
statesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .statesTags)
|
||||||
|
stores = try container.decodeIfPresent(String.self, forKey: .stores)
|
||||||
|
storesDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .storesDebugTags)
|
||||||
|
storesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .storesTags)
|
||||||
|
traces = try container.decodeIfPresent(String.self, forKey: .traces)
|
||||||
|
tracesFromIngredients = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .tracesFromIngredients)
|
||||||
|
tracesHierarchy = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .tracesHierarchy)
|
||||||
|
tracesDebugTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .tracesDebugTags)
|
||||||
|
tracesFromUser = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .tracesFromUser)
|
||||||
|
tracesLc = try container.decodeIfPresent(String.self, forKey: .tracesLc)
|
||||||
|
tracesTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .tracesTags)
|
||||||
|
if container.contains(.unknownIngredientsN) {
|
||||||
|
if try container.decodeNil(forKey: .unknownIngredientsN) {
|
||||||
|
unknownIngredientsN = nil
|
||||||
|
} else {
|
||||||
|
if let intValue = try? container.decode(
|
||||||
|
Float.self, forKey: .unknownIngredientsN)
|
||||||
|
{
|
||||||
|
unknownIngredientsN = intValue
|
||||||
|
} else if let stringValue = try? container.decode(
|
||||||
|
String.self, forKey: .unknownIngredientsN)
|
||||||
|
{
|
||||||
|
unknownIngredientsN = Float(stringValue)
|
||||||
|
} else {
|
||||||
|
// If decoding as both Float and String fails, handle the error accordingly
|
||||||
|
throw DecodingError.dataCorruptedError(
|
||||||
|
forKey: .unknownIngredientsN,
|
||||||
|
in: container,
|
||||||
|
debugDescription: "Unable to decode unknownIngredientsN"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unknownIngredientsN = nil
|
||||||
|
}
|
||||||
|
unknownNutrientsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .unknownNutrientsTags)
|
||||||
|
updateKey = try container.decodeIfPresent(
|
||||||
|
String.self, forKey: .updateKey)
|
||||||
|
vitaminsPrevTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .vitaminsPrevTags)
|
||||||
|
vitaminsTags = try container.decodeIfPresent(
|
||||||
|
[String].self, forKey: .vitaminsTags)
|
||||||
|
|
||||||
|
// Check for null value
|
||||||
|
if container.contains(.productQuantity) {
|
||||||
|
if try container.decodeNil(forKey: .productQuantity) {
|
||||||
|
productQuantity = nil
|
||||||
|
} else {
|
||||||
|
// Try to decode as Float
|
||||||
|
if let floatValue = try? container.decode(
|
||||||
|
Float.self, forKey: .productQuantity)
|
||||||
|
{
|
||||||
|
productQuantity = floatValue
|
||||||
|
} else if let stringValue = try? container.decode(
|
||||||
|
String.self, forKey: .productQuantity)
|
||||||
|
{
|
||||||
|
// If decoding as Float fails, try to decode as String
|
||||||
|
productQuantity = Float(stringValue)
|
||||||
|
} else {
|
||||||
|
// If decoding as both Float and String fails, handle the error accordingly
|
||||||
|
throw DecodingError.dataCorruptedError(
|
||||||
|
forKey: .productQuantity,
|
||||||
|
in: container,
|
||||||
|
debugDescription: "Unable to decode productQuantity"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
productQuantity = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... (initialize other properties)
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Sources/OpenFoodFacts/Schemas/ProductResponse.swift
Normal file
13
Sources/OpenFoodFacts/Schemas/ProductResponse.swift
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
public struct ProductResponse: Codable, ObjectDebugger {
|
||||||
|
public var product: Product?
|
||||||
|
public var code: String?
|
||||||
|
public var status: Int? // or Bool, depending on your needs
|
||||||
|
public var statusVerbose: String?
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case product
|
||||||
|
case code
|
||||||
|
case status
|
||||||
|
case statusVerbose = "status_verbose"
|
||||||
|
}
|
||||||
|
}
|
||||||
98
Sources/OpenFoodFacts/Schemas/SearchNutriment.swift
Normal file
98
Sources/OpenFoodFacts/Schemas/SearchNutriment.swift
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
public enum SearchNutriment: String, Codable {
|
||||||
|
case energy // Energy
|
||||||
|
case energyFromFat = "energy-from-fat" // Energy from fat
|
||||||
|
case fat // Fat
|
||||||
|
case saturatedFat = "saturated-fat" // Saturated fat
|
||||||
|
case butyricAcid = "butyric-acid" // Butyric acid (4:0)
|
||||||
|
case caproicAcid = "caproic-acid" // Caproic acid (6:0)
|
||||||
|
case caprylicAcid = "caprylic-acid" // Caprylic acid (8:0)
|
||||||
|
case capricAcid = "capric-acid" // Capric acid (10:0)
|
||||||
|
case lauricAcid = "lauric-acid" // Lauric acid (12:0)
|
||||||
|
case myristicAcid = "myristic-acid" // Myristic acid (14:0)
|
||||||
|
case palmiticAcid = "palmitic-acid" // Palmitic acid (16:0)
|
||||||
|
case stearicAcid = "stearic-acid" // Stearic acid (18:0)
|
||||||
|
case arachidicAcid = "arachidic-acid" // Arachidic acid (20:0)
|
||||||
|
case behenicAcid = "behenic-acid" // Behenic acid (22:0)
|
||||||
|
case lignocericAcid = "lignoceric-acid" // Lignoceric acid (24:0)
|
||||||
|
case ceroticAcid = "cerotic-acid" // Cerotic acid (26:0)
|
||||||
|
case montanicAcid = "montanic-acid" // Montanic acid (28:0)
|
||||||
|
case melissicAcid = "melissic-acid" // Melissic acid (30:0)
|
||||||
|
case monounsaturatedFat = "monounsaturated-fat" // Monounsaturated fat
|
||||||
|
case polyunsaturatedFat = "polyunsaturated-fat" // Polyunsaturated fat
|
||||||
|
case omega3Fat = "omega-3-fat" // Omega 3 fatty acids
|
||||||
|
case alphaLinolenicAcid = "alpha-linolenic-acid" // Alpha-linolenic acid / ALA (18:3 n-3)
|
||||||
|
case eicosapentaenoicAcid = "eicosapentaenoic-acid" // Eicosapentaenoic acid / EPA (20:5 n-3)
|
||||||
|
case docosahexaenoicAcid = "docosahexaenoic-acid" // Docosahexaenoic acid / DHA (22:6 n-3)
|
||||||
|
case omega6Fat = "omega-6-fat" // Omega 6 fatty acids
|
||||||
|
case linoleicAcid = "linoleic-acid" // Linoleic acid / LA (18:2 n-6)
|
||||||
|
case arachidonicAcid = "arachidonic-acid" // Arachidonic acid / AA / ARA (20:4 n-6)
|
||||||
|
case gammaLinolenicAcid = "gamma-linolenic-acid" // Gamma-linolenic acid / GLA (18:3 n-6)
|
||||||
|
case dihomoGammaLinolenicAcid = "dihomo-gamma-linolenic-acid" // Dihomo-gamma-linolenic acid / DGLA (20:3 n-6)
|
||||||
|
case omega9Fat = "omega-9-fat" // Omega 9 fatty acids
|
||||||
|
case oleicAcid = "oleic-acid" // Oleic acid (18:1 n-9)
|
||||||
|
case elaidicAcid = "elaidic-acid" // Elaidic acid (18:1 n-9)
|
||||||
|
case gondoicAcid = "gondoic-acid" // Gondoic acid (20:1 n-9)
|
||||||
|
case meadAcid = "mead-acid" // Mead acid (20:3 n-9)
|
||||||
|
case erucicAcid = "erucic-acid" // Erucic acid (22:1 n-9)
|
||||||
|
case nervonicAcid = "nervonic-acid" // Nervonic acid (24:1 n-9)
|
||||||
|
case transFat = "trans-fat" // Trans fat
|
||||||
|
case cholesterol // Cholesterol
|
||||||
|
case carbohydrates // Carbohydrate
|
||||||
|
case sugars // Sugars
|
||||||
|
case sucrose // Sucrose
|
||||||
|
case glucose // Glucose
|
||||||
|
case fructose // Fructose
|
||||||
|
case lactose // Lactose
|
||||||
|
case maltose // Maltose
|
||||||
|
case maltodextrins // Maltodextrins
|
||||||
|
case starch // Starch
|
||||||
|
case polyols // Sugar alcohols (Polyols)
|
||||||
|
case fiber // Dietary fiber
|
||||||
|
case proteins // Proteins
|
||||||
|
case casein // Casein
|
||||||
|
case serumProteins = "serum-proteins" // Serum proteins
|
||||||
|
case nucleotides // Nucleotides
|
||||||
|
case salt // Salt
|
||||||
|
case sodium // Sodium
|
||||||
|
case alcohol // Alcohol
|
||||||
|
case vitaminA = "vitamin-a" // Vitamin A
|
||||||
|
case betaCarotene = "beta-carotene" // Beta carotene
|
||||||
|
case vitaminD = "vitamin-d" // Vitamin D
|
||||||
|
case vitaminE = "vitamin-e" // Vitamin E
|
||||||
|
case vitaminK = "vitamin-k" // Vitamin K
|
||||||
|
case vitaminC = "vitamin-c" // Vitamin C (ascorbic acid)
|
||||||
|
case vitaminB1 = "vitamin-b1" // Vitamin B1 (Thiamin)
|
||||||
|
case vitaminB2 = "vitamin-b2" // Vitamin B2 (Riboflavin)
|
||||||
|
case vitaminPP = "vitamin-pp" // Vitamin B3 / Vitamin PP (Niacin)
|
||||||
|
case vitaminB6 = "vitamin-b6" // Vitamin B6 (Pyridoxin)
|
||||||
|
case vitaminB9 = "vitamin-b9" // Vitamin B9 (Folic acid / Folates)
|
||||||
|
case vitaminB12 = "vitamin-b12" // Vitamin B12 (Cobalamin)
|
||||||
|
case biotin // Biotin
|
||||||
|
case pantothenicAcid = "pantothenic-acid" // Pantothenic acid / Pantothenate (Vitamin B5)
|
||||||
|
case silica // Silica
|
||||||
|
case bicarbonate // Bicarbonate
|
||||||
|
case potassium // Potassium
|
||||||
|
case chloride // Chloride
|
||||||
|
case calcium // Calcium
|
||||||
|
case phosphorus // Phosphorus
|
||||||
|
case iron // Iron
|
||||||
|
case magnesium // Magnesium
|
||||||
|
case zinc // Zinc
|
||||||
|
case copper // Copper
|
||||||
|
case manganese // Manganese
|
||||||
|
case fluoride // Fluoride
|
||||||
|
case selenium // Selenium
|
||||||
|
case chromium // Chromium
|
||||||
|
case molybdenum // Molybdenum
|
||||||
|
case iodine // Iodine
|
||||||
|
case caffeine // Caffeine
|
||||||
|
case taurine // Taurine
|
||||||
|
case pH // pH
|
||||||
|
case fruitsVegetablesNuts = "fruits-vegetables-nuts" // Fruits, vegetables, and nuts (minimum)
|
||||||
|
case collagenMeatProteinRatio = "collagen-meat-protein-ratio" // Collagen/Meat protein ratio (maximum)
|
||||||
|
case cocoa // Cocoa (minimum)
|
||||||
|
case chlorophyll = "chlorophyll" // Chlorophyll
|
||||||
|
case carbonFootprint = "carbon-footprint" // Carbon footprint / CO2 emissions
|
||||||
|
case nutritionScoreFR = "nutrition-score-fr" // Experimental nutrition score
|
||||||
|
case nutritionScoreUK = "nutrition-score-uk" // Nutrition score - UK
|
||||||
|
}
|
||||||
14
Sources/OpenFoodFacts/Schemas/SearchResponse.swift
Normal file
14
Sources/OpenFoodFacts/Schemas/SearchResponse.swift
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
public struct SearchResponse: Codable, ObjectDebugger {
|
||||||
|
public var count: Int
|
||||||
|
public var page: Int
|
||||||
|
public var pageCount: Int
|
||||||
|
public var pageSize: Int
|
||||||
|
public var products: [Product]?
|
||||||
|
public var skip: Int
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case count, page, products, skip
|
||||||
|
case pageCount = "page_count"
|
||||||
|
case pageSize = "page_size"
|
||||||
|
}
|
||||||
|
}
|
||||||
17
Sources/OpenFoodFacts/Schemas/SearchTag.swift
Normal file
17
Sources/OpenFoodFacts/Schemas/SearchTag.swift
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
public enum SearchTag: String, Codable {
|
||||||
|
case brands // Brands
|
||||||
|
case categories // Categories
|
||||||
|
case packaging // Packaging
|
||||||
|
case labels // Labels
|
||||||
|
case origins // Origins of ingredients
|
||||||
|
case manufacturingPlaces = "manufacturing_places" // Manufacturing or processing places
|
||||||
|
case embCodes = "emb_codes" // Packager codes
|
||||||
|
case purchasePlaces = "purchase_places" // Purchase places
|
||||||
|
case stores // Stores
|
||||||
|
case countries // Countries
|
||||||
|
case additives // Additives
|
||||||
|
case allergens // Allergens
|
||||||
|
case traces // Traces
|
||||||
|
case nutritionGrades = "nutrition_grades" // Nutrition grades
|
||||||
|
case states // States
|
||||||
|
}
|
||||||
14
Sources/OpenFoodFacts/Schemas/SelectedImage.swift
Normal file
14
Sources/OpenFoodFacts/Schemas/SelectedImage.swift
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
public class SelectedImage: Codable, ObjectDebugger {
|
||||||
|
public var display: SelectedImageItem?
|
||||||
|
public var small: SelectedImageItem?
|
||||||
|
public var thumb: SelectedImageItem?
|
||||||
|
|
||||||
|
public init(
|
||||||
|
display: SelectedImageItem?, small: SelectedImageItem?,
|
||||||
|
thumb: SelectedImageItem?
|
||||||
|
) {
|
||||||
|
self.display = display
|
||||||
|
self.small = small
|
||||||
|
self.thumb = thumb
|
||||||
|
}
|
||||||
|
}
|
||||||
15
Sources/OpenFoodFacts/Schemas/SelectedImageItem.swift
Normal file
15
Sources/OpenFoodFacts/Schemas/SelectedImageItem.swift
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
public struct SelectedImageItem: Codable, ObjectDebugger {
|
||||||
|
public var en: String?
|
||||||
|
public var fr: String?
|
||||||
|
public var pl: String?
|
||||||
|
|
||||||
|
public var url: String {
|
||||||
|
[en, fr, pl].compactMap { $0 }.first ?? ""
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(en: String?, fr: String?, pl: String?) {
|
||||||
|
self.en = en
|
||||||
|
self.fr = fr
|
||||||
|
self.pl = pl
|
||||||
|
}
|
||||||
|
}
|
||||||
14
Sources/OpenFoodFacts/Schemas/SelectedImages.swift
Normal file
14
Sources/OpenFoodFacts/Schemas/SelectedImages.swift
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
public struct SelectedImages: Codable, ObjectDebugger {
|
||||||
|
public var front: SelectedImage?
|
||||||
|
public var ingredients: SelectedImage?
|
||||||
|
public var nutrition: SelectedImage?
|
||||||
|
|
||||||
|
public init(
|
||||||
|
front: SelectedImage?, ingredients: SelectedImage?,
|
||||||
|
nutrition: SelectedImage?
|
||||||
|
) {
|
||||||
|
self.front = front
|
||||||
|
self.ingredients = ingredients
|
||||||
|
self.nutrition = nutrition
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Sources/OpenFoodFacts/Schemas/Source.swift
Normal file
19
Sources/OpenFoodFacts/Schemas/Source.swift
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
public struct Source: Codable, ObjectDebugger {
|
||||||
|
public let fields: [String] = []
|
||||||
|
public let id: String? = nil
|
||||||
|
public let images: [String] = []
|
||||||
|
public let importT: Int = 0
|
||||||
|
public let manufacturer: String? = nil
|
||||||
|
public let name: String? = nil
|
||||||
|
public let url: String? = nil
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case fields
|
||||||
|
case id
|
||||||
|
case images
|
||||||
|
case importT = "import_t"
|
||||||
|
case manufacturer
|
||||||
|
case name
|
||||||
|
case url
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
|
|
||||||
public struct Images: Codable {
|
|
||||||
public var otherData: [String: Data] = [:]
|
|
||||||
|
|
||||||
mutating func setDetail<T: Encodable>(key: String, value: T) throws {
|
|
||||||
let encodedValue = try JSONEncoder().encode(value)
|
|
||||||
otherData[key] = encodedValue
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDetail<T: Decodable>(key: String, type: T.Type) throws -> T? {
|
|
||||||
guard let data = otherData[key] else { return nil }
|
|
||||||
return try JSONDecoder().decode(type, from: data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
public struct Ingredient: Codable, ObjectDebugger {
|
|
||||||
public var fromPalmOil: String? = nil
|
|
||||||
public var id: String? = nil
|
|
||||||
public var origin: String? = nil
|
|
||||||
public var percent: Float? = nil
|
|
||||||
public var rank: Float? = 0
|
|
||||||
public var text: String? = nil
|
|
||||||
public var vegan: String? = nil
|
|
||||||
public var vegetarian: String? = nil
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
|
||||||
case fromPalmOil = "from_palm_oil"
|
|
||||||
case id
|
|
||||||
case origin
|
|
||||||
case percent
|
|
||||||
case rank
|
|
||||||
case text
|
|
||||||
case vegan
|
|
||||||
case vegetarian
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
|
|
||||||
public struct LanguagesCodes: Codable, ObjectDebugger {
|
|
||||||
public var en: Float? = nil
|
|
||||||
public var fr: Float? = nil
|
|
||||||
public var pl: Float? = nil
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
public struct NutrientLevels: Codable, ObjectDebugger {
|
|
||||||
public var fat: String? = nil
|
|
||||||
public var salt: String? = nil
|
|
||||||
public var saturatedFat: String? = nil
|
|
||||||
public var sugars: String? = nil
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
|
||||||
case fat
|
|
||||||
case salt
|
|
||||||
case saturatedFat = "saturated-fat"
|
|
||||||
case sugars
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
public struct Nutriments: Codable, ObjectDebugger {
|
|
||||||
public var calcium: Float?
|
|
||||||
public var calciumValue: Float?
|
|
||||||
public var calcium100G: Float?
|
|
||||||
public var calciumServing: Float?
|
|
||||||
public var calciumUnit: String?
|
|
||||||
|
|
||||||
public var carbohydrates: Float?
|
|
||||||
public var carbohydratesValue: Float?
|
|
||||||
public var carbohydrates100G: Float?
|
|
||||||
public var carbohydratesServing: Float?
|
|
||||||
public var carbohydratesUnit: String?
|
|
||||||
|
|
||||||
public var carbonFootprintFromKnownIngredientsProduct: Float?
|
|
||||||
public var carbonFootprintFromKnownIngredients100G: Float?
|
|
||||||
public var carbonFootprintFromKnownIngredientsServing: Float?
|
|
||||||
|
|
||||||
public var cholesterol: Float?
|
|
||||||
public var cholesterolValue: Float?
|
|
||||||
public var cholesterol100G: Float?
|
|
||||||
public var cholesterolServing: Float?
|
|
||||||
public var cholesterolUnit: String?
|
|
||||||
|
|
||||||
public var energy: Float?
|
|
||||||
public var energyKcal: Float?
|
|
||||||
public var energyKj: Float?
|
|
||||||
public var energyValue: Float?
|
|
||||||
public var energyKcalValue: Float?
|
|
||||||
public var energyKjValue: Float?
|
|
||||||
public var energy100G: Float?
|
|
||||||
public var energyKcal100G: Float?
|
|
||||||
public var energyKj100G: Float?
|
|
||||||
public var energyServing: Float?
|
|
||||||
public var energyKcalServing: Double?
|
|
||||||
public var energyKjServing: Float?
|
|
||||||
public var energyUnit: String?
|
|
||||||
public var energyKcalUnit: String?
|
|
||||||
public var energyKjUnit: String?
|
|
||||||
|
|
||||||
public var fat: Float?
|
|
||||||
public var fatValue: Float?
|
|
||||||
public var fat100G: Float?
|
|
||||||
public var fatServing: Float?
|
|
||||||
public var fatUnit: String?
|
|
||||||
|
|
||||||
public var fiber: Float?
|
|
||||||
public var fiberValue: Float?
|
|
||||||
public var fiber100G: Float?
|
|
||||||
public var fiberServing: Float?
|
|
||||||
public var fiberUnit: String?
|
|
||||||
|
|
||||||
public var fruitsVegetablesNutsEstimateFromIngredients100G: Float?
|
|
||||||
|
|
||||||
public var iron: Float?
|
|
||||||
public var ironValue: Float?
|
|
||||||
public var iron100G: Float?
|
|
||||||
public var ironServing: Float?
|
|
||||||
public var ironUnit: String?
|
|
||||||
|
|
||||||
public var novaGroup: Float?
|
|
||||||
public var novaGroup100G: Float?
|
|
||||||
public var novaGroupServing: Float?
|
|
||||||
|
|
||||||
public var proteins: Float?
|
|
||||||
public var proteinsValue: Float?
|
|
||||||
public var proteins100G: Float?
|
|
||||||
public var proteinsServing: Float?
|
|
||||||
public var proteinsUnit: String?
|
|
||||||
|
|
||||||
public var salt: Float?
|
|
||||||
public var saltValue: Float?
|
|
||||||
public var salt100G: Float?
|
|
||||||
public var saltServing: Float?
|
|
||||||
public var saltUnit: String?
|
|
||||||
|
|
||||||
public var saturatedFat: Float?
|
|
||||||
public var saturatedFatValue: Float?
|
|
||||||
public var saturatedFat100G: Float?
|
|
||||||
public var saturatedFatServing: Float?
|
|
||||||
public var saturatedFatUnit: String?
|
|
||||||
|
|
||||||
public var sodium: Float?
|
|
||||||
public var sodiumValue: Float?
|
|
||||||
public var sodium100G: Float?
|
|
||||||
public var sodiumServing: Float?
|
|
||||||
public var sodiumUnit: String?
|
|
||||||
|
|
||||||
public var sugars: Float?
|
|
||||||
public var sugarsValue: Float?
|
|
||||||
public var sugars100G: Float?
|
|
||||||
public var sugarsServing: Float?
|
|
||||||
public var sugarsUnit: String?
|
|
||||||
|
|
||||||
public var transFat: Float?
|
|
||||||
public var transFatValue: Float?
|
|
||||||
public var transFat100G: Float?
|
|
||||||
public var transFatServing: Float?
|
|
||||||
public var transFatUnit: String?
|
|
||||||
|
|
||||||
public var vitaminA: Float?
|
|
||||||
public var vitaminAValue: Float?
|
|
||||||
public var vitaminA100G: Float?
|
|
||||||
public var vitaminAServing: Float?
|
|
||||||
public var vitaminAUnit: String?
|
|
||||||
|
|
||||||
public var vitaminC: Float?
|
|
||||||
public var vitaminCValue: Float?
|
|
||||||
public var vitaminC100G: Float?
|
|
||||||
public var vitaminCServing: Float?
|
|
||||||
public var vitaminCUnit: String?
|
|
||||||
|
|
||||||
public var vitaminD: Float?
|
|
||||||
public var vitaminDValue: Float?
|
|
||||||
public var vitaminD100G: Float?
|
|
||||||
public var vitaminDServing: Float?
|
|
||||||
public var vitaminDUnit: String?
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
|
||||||
case calcium
|
|
||||||
case calciumValue = "calcium_value"
|
|
||||||
case calcium100G = "calcium_100g"
|
|
||||||
case calciumServing = "calcium_serving"
|
|
||||||
case calciumUnit = "calcium_unit"
|
|
||||||
|
|
||||||
case carbohydrates
|
|
||||||
case carbohydratesValue = "carbohydrates_value"
|
|
||||||
case carbohydrates100G = "carbohydrates_100g"
|
|
||||||
case carbohydratesServing = "carbohydrates_serving"
|
|
||||||
case carbohydratesUnit = "carbohydrates_unit"
|
|
||||||
|
|
||||||
case carbonFootprintFromKnownIngredientsProduct = "carbon-footprint-from-known-ingredients_product"
|
|
||||||
case carbonFootprintFromKnownIngredients100G = "carbon-footprint-from-known-ingredients_100g"
|
|
||||||
case carbonFootprintFromKnownIngredientsServing = "carbon-footprint-from-known-ingredients_serving"
|
|
||||||
|
|
||||||
case cholesterol
|
|
||||||
case cholesterolValue = "cholesterol_value"
|
|
||||||
case cholesterol100G = "cholesterol_100g"
|
|
||||||
case cholesterolServing = "cholesterol_serving"
|
|
||||||
case cholesterolUnit = "cholesterol_unit"
|
|
||||||
|
|
||||||
case energy
|
|
||||||
case energyKcal = "energy-kcal"
|
|
||||||
case energyKj = "energy-kj"
|
|
||||||
case energyValue = "energy_value"
|
|
||||||
case energyKcalValue = "energy-kcal_value"
|
|
||||||
case energyKjValue = "energy-kj_value"
|
|
||||||
case energy100G = "energy_100g"
|
|
||||||
case energyKcal100G = "energy-kcal_100g"
|
|
||||||
case energyKj100G = "energy-kj_100g"
|
|
||||||
case energyServing = "energy_serving"
|
|
||||||
case energyKcalServing = "energy-kcal_serving"
|
|
||||||
case energyKjServing = "energy-kj_serving"
|
|
||||||
case energyUnit = "energy_unit"
|
|
||||||
case energyKcalUnit = "energy-kcal_unit"
|
|
||||||
case energyKjUnit = "energy-kj_unit"
|
|
||||||
|
|
||||||
case fat
|
|
||||||
case fatValue = "fat_value"
|
|
||||||
case fat100G = "fat_100g"
|
|
||||||
case fatServing = "fat_serving"
|
|
||||||
case fatUnit = "fat_unit"
|
|
||||||
|
|
||||||
case fiber
|
|
||||||
case fiberValue = "fiber_value"
|
|
||||||
case fiber100G = "fiber_100g"
|
|
||||||
case fiberServing = "fiber_serving"
|
|
||||||
case fiberUnit = "fiber_unit"
|
|
||||||
|
|
||||||
case fruitsVegetablesNutsEstimateFromIngredients100G = "fruits-vegetables-nuts-estimate-from-ingredients_100g"
|
|
||||||
|
|
||||||
case iron
|
|
||||||
case ironValue = "iron_value"
|
|
||||||
case iron100G = "iron_100g"
|
|
||||||
case ironServing = "iron_serving"
|
|
||||||
case ironUnit = "iron_unit"
|
|
||||||
|
|
||||||
case novaGroup
|
|
||||||
case novaGroup100G = "nova-group_100g"
|
|
||||||
case novaGroupServing = "nova-group_serving"
|
|
||||||
|
|
||||||
case proteins
|
|
||||||
case proteinsValue = "proteins_value"
|
|
||||||
case proteins100G = "proteins_100g"
|
|
||||||
case proteinsServing = "proteins_serving"
|
|
||||||
case proteinsUnit = "proteins_unit"
|
|
||||||
|
|
||||||
case salt
|
|
||||||
case saltValue = "salt_value"
|
|
||||||
case salt100G = "salt_100g"
|
|
||||||
case saltServing = "salt_serving"
|
|
||||||
case saltUnit = "salt_unit"
|
|
||||||
|
|
||||||
case saturatedFat = "saturated-fat"
|
|
||||||
case saturatedFatValue = "saturated-fat_value"
|
|
||||||
case saturatedFat100G = "saturated-fat_100g"
|
|
||||||
case saturatedFatServing = "saturated-fat_serving"
|
|
||||||
case saturatedFatUnit = "saturated-fat_unit"
|
|
||||||
|
|
||||||
case sodium
|
|
||||||
case sodiumValue = "sodium_value"
|
|
||||||
case sodium100G = "sodium_100g"
|
|
||||||
case sodiumServing = "sodium_serving"
|
|
||||||
case sodiumUnit = "sodium_unit"
|
|
||||||
|
|
||||||
case sugars
|
|
||||||
case sugarsValue = "sugars_value"
|
|
||||||
case sugars100G = "sugars_100g"
|
|
||||||
case sugarsServing = "sugars_serving"
|
|
||||||
case sugarsUnit = "sugars_unit"
|
|
||||||
|
|
||||||
case transFat = "trans-fat"
|
|
||||||
case transFatValue = "trans-fat_value"
|
|
||||||
case transFat100G = "trans-fat_100g"
|
|
||||||
case transFatServing = "trans-fat_serving"
|
|
||||||
case transFatUnit = "trans-fat_unit"
|
|
||||||
|
|
||||||
case vitaminA = "vitamin-a"
|
|
||||||
case vitaminAValue = "vitamin-a_value"
|
|
||||||
case vitaminA100G = "vitamin-a_100g"
|
|
||||||
case vitaminAServing = "vitamin-a_serving"
|
|
||||||
case vitaminAUnit = "vitamin-a_unit"
|
|
||||||
|
|
||||||
case vitaminC = "vitamin-c"
|
|
||||||
case vitaminCValue = "vitamin-c_value"
|
|
||||||
case vitaminC100G = "vitamin-c_100g"
|
|
||||||
case vitaminCServing = "vitamin-c_serving"
|
|
||||||
case vitaminCUnit = "vitamin-c_unit"
|
|
||||||
|
|
||||||
case vitaminD = "vitamin-d"
|
|
||||||
case vitaminDValue = "vitamin-d_value"
|
|
||||||
case vitaminD100G = "vitamin-d_100g"
|
|
||||||
case vitaminDServing = "vitamin-d_serving"
|
|
||||||
case vitaminDUnit = "vitamin-d_unit"
|
|
||||||
|
|
||||||
// case other
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
public protocol ObjectDebugger: CustomStringConvertible {
|
|
||||||
var description: String { get }
|
|
||||||
}
|
|
||||||
|
|
||||||
public extension ObjectDebugger {
|
|
||||||
var description: String {
|
|
||||||
var description = "\(type(of: self))("
|
|
||||||
let mirror = Mirror(reflecting: self)
|
|
||||||
|
|
||||||
for (label, value) in mirror.children {
|
|
||||||
if let label = label {
|
|
||||||
description += "\(label): \(value), "
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the trailing comma and space
|
|
||||||
description = String(description.dropLast(2))
|
|
||||||
description += ")"
|
|
||||||
|
|
||||||
return description
|
|
||||||
}
|
|
||||||
|
|
||||||
private func prettyPrint(object: Any, indentation: String = "") -> String {
|
|
||||||
var description = "\(type(of: object)) {"
|
|
||||||
|
|
||||||
let mirror = Mirror(reflecting: object)
|
|
||||||
|
|
||||||
for (label, value) in mirror.children {
|
|
||||||
if let label = label {
|
|
||||||
let childDescription: String
|
|
||||||
switch value {
|
|
||||||
case let nestedObject as CustomStringConvertible:
|
|
||||||
childDescription = prettyPrint(object: nestedObject, indentation: "\(indentation) ")
|
|
||||||
case let stringValue as String:
|
|
||||||
childDescription = "\"\(stringValue)\""
|
|
||||||
case let floatValue as Float:
|
|
||||||
childDescription = "\(floatValue)"
|
|
||||||
case let intValue as Int:
|
|
||||||
childDescription = "\(intValue)"
|
|
||||||
case let optionalValue as CustomStringConvertible?:
|
|
||||||
if let unwrapped = optionalValue {
|
|
||||||
childDescription = "\(unwrapped)"
|
|
||||||
} else {
|
|
||||||
childDescription = "nil"
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
childDescription = "\(value)"
|
|
||||||
}
|
|
||||||
|
|
||||||
description += "\n\(indentation) \(label): \(childDescription)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
description += "\n\(indentation)}"
|
|
||||||
return description
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
public enum PerlOperator: String {
|
|
||||||
case lt, lte, gt, gte, eq
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum PerlFormat: String {
|
|
||||||
case json, xml, jqm
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct SearchNutrimentEntry {
|
|
||||||
public let nutriment: SearchNutriment
|
|
||||||
public let op: PerlOperator
|
|
||||||
public let value: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct SearchTagsEntry {
|
|
||||||
public let tag: SearchTag
|
|
||||||
public let value: String
|
|
||||||
public let contains: Bool = true
|
|
||||||
}
|
|
||||||
|
|
||||||
//https://wiki.openfoodfacts.org/API/Read/Search#Parameters
|
|
||||||
public struct PerlSearchQuery {
|
|
||||||
public var searchTerms: String
|
|
||||||
public var searchTags: [SearchTagsEntry]? // tagtype_i=SearchTag — i as #element (starting from 0); (tag_contains_i|tag_does_not_contain_i)=String
|
|
||||||
public var searchNutriment: [SearchNutrimentEntry]? // nutriment_i=SearchNutriment — i as #element (starting from 0); nutriment_compare_i=PerlOperator; nutriment_value_i=String
|
|
||||||
public var page: Int = 1 // Pagination
|
|
||||||
public var format: PerlFormat // json=1 | xml=1 | jqm=1
|
|
||||||
|
|
||||||
public init(searchTerms: String, searchTags: [SearchTagsEntry]? = nil, searchNutriment: [SearchNutrimentEntry]? = nil, page: Int = 1, format: PerlFormat = .json) {
|
|
||||||
self.searchTerms = searchTerms
|
|
||||||
self.searchTags = searchTags
|
|
||||||
self.searchNutriment = searchNutriment
|
|
||||||
self.page = page
|
|
||||||
self.format = format
|
|
||||||
}
|
|
||||||
|
|
||||||
public func makeToRequest() -> String {
|
|
||||||
var _searchTags: String?
|
|
||||||
var _searchNutriment: String?
|
|
||||||
let _format: String = "\(format.rawValue)=1"
|
|
||||||
let _page: String = "page=\(page)"
|
|
||||||
if let tags = searchTags {
|
|
||||||
_searchTags = tags.enumerated().map { i, v in
|
|
||||||
return "tagtype_\(i)=\(v.tag.rawValue)&tag_contains_\(i)=\(v.contains ? "contains" : "does_not_contain")&tag_\(i)=\(v.value)"
|
|
||||||
}.joined(separator: "&")
|
|
||||||
}
|
|
||||||
if let nutriments = searchNutriment {
|
|
||||||
_searchNutriment = nutriments.enumerated().map { i, v in
|
|
||||||
return "nutriment_\(i)=\(v.nutriment.rawValue)&nutriment_compare_\(i)=\(v.op.rawValue)&nutriment_value_\(i)=\(v.nutriment.rawValue)"
|
|
||||||
}.joined(separator: "&")
|
|
||||||
}
|
|
||||||
|
|
||||||
return "search_terms=\(searchTerms)\(_searchTags != nil ? "&\(_searchTags!)" : "")\(_searchNutriment != nil ? "&\(_searchNutriment!)" : "")&\(_page)&\(_format)"
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,726 +0,0 @@
|
|||||||
public class Product: Codable, ObjectDebugger {
|
|
||||||
// public var images: Images? = Images()
|
|
||||||
public var ingredients: [Ingredient]? = []
|
|
||||||
public var languagesCodes: LanguagesCodes?
|
|
||||||
public var nutrientLevels: NutrientLevels?
|
|
||||||
public var nutriments: Nutriments? = Nutriments()
|
|
||||||
public var selectedImages: SelectedImages?
|
|
||||||
public var sources: [Source]? = []
|
|
||||||
public var additivesN: Float?
|
|
||||||
public var additivesOldN: Float?
|
|
||||||
public var additivesOriginalTags: [String]?
|
|
||||||
public var additivesOldTags: [String]?
|
|
||||||
public var additivesPrevOriginalTags: [String]?
|
|
||||||
public var additivesDebugTags: [String]?
|
|
||||||
public var additivesTags: [String]?
|
|
||||||
public var allergens: String?
|
|
||||||
public var allergensFromIngredients: String?
|
|
||||||
public var allergensFromUser: String?
|
|
||||||
public var allergensHierarchy: [String]?
|
|
||||||
public var allergensLc: String?
|
|
||||||
public var allergensTags: [String]?
|
|
||||||
public var aminoAcidsPrevTags: [String]?
|
|
||||||
public var aminoAcidsTags: [String]?
|
|
||||||
public var brands: String?
|
|
||||||
public var brandsDebugTags: [String]?
|
|
||||||
public var brandsTags: [String]?
|
|
||||||
public var carbonFootprintPercentOfKnownIngredients: Float?
|
|
||||||
public var carbonFootprintFromKnownIngredientsDebug: String?
|
|
||||||
public var categories: String?
|
|
||||||
public var categoriesHierarchy: [String]?
|
|
||||||
public var categoriesLc: String?
|
|
||||||
public var categoriesPropertiesTags: [String]?
|
|
||||||
public var categoriesTags: [String]?
|
|
||||||
public var checkersTags: [String]?
|
|
||||||
public var citiesTags: [String]?
|
|
||||||
public var code: String?
|
|
||||||
public var codesTags: [String]?
|
|
||||||
public var comparedToCategory: String?
|
|
||||||
public var complete: Float?
|
|
||||||
public var completedT: Float?
|
|
||||||
public var completeness: Double?
|
|
||||||
public var conservationConditions: String?
|
|
||||||
public var countries: String?
|
|
||||||
public var countriesHierarchy: [String]?
|
|
||||||
public var countriesLc: String?
|
|
||||||
public var countriesDebugTags: [String]?
|
|
||||||
public var countriesTags: [String]?
|
|
||||||
public var correctorsTags: [String]?
|
|
||||||
public var createdT: Float?
|
|
||||||
public var creator: String?
|
|
||||||
public var dataQualityBugsTags: [String]?
|
|
||||||
public var dataQualityErrorsTags: [String]?
|
|
||||||
public var dataQualityInfoTags: [String]?
|
|
||||||
public var dataQualityTags: [String]?
|
|
||||||
public var dataQualityWarningsTags: [String]?
|
|
||||||
public var dataSources: String?
|
|
||||||
public var dataSourcesTags: [String]?
|
|
||||||
public var debugParamSortedLangs: [String]?
|
|
||||||
public var editorsTags: [String]?
|
|
||||||
public var embCodes: String?
|
|
||||||
public var embCodesDebugTags: [String]?
|
|
||||||
public var embCodesOrig: String?
|
|
||||||
public var embCodesTags: [String]?
|
|
||||||
public var entryDatesTags: [String]?
|
|
||||||
public var expirationDate: String?
|
|
||||||
public var expirationDateDebugTags: [String]?
|
|
||||||
public var fruitsVegetablesNuts100GEstimate: Float?
|
|
||||||
public var genericName: String?
|
|
||||||
public var id: String?
|
|
||||||
public var imageFrontSmallUrl: String?
|
|
||||||
public var imageFrontThumbUrl: String?
|
|
||||||
public var imageFrontUrl: String?
|
|
||||||
public var imageIngredientsUrl: String?
|
|
||||||
public var imageIngredientsSmallUrl: String?
|
|
||||||
public var imageIngredientsThumbUrl: String?
|
|
||||||
public var imageNutritionSmallUrl: String?
|
|
||||||
public var imageNutritionThumbUrl: String?
|
|
||||||
public var imageNutritionUrl: String?
|
|
||||||
public var imageSmallUrl: String?
|
|
||||||
public var imageThumbUrl: String?
|
|
||||||
public var imageUrl: String?
|
|
||||||
public var informersTags: [String]?
|
|
||||||
public var ingredientsAnalysisTags: [String]?
|
|
||||||
public var ingredientsDebug: [String?]?
|
|
||||||
public var ingredientsFromOrThatMayBeFromPalmOilN: Float?
|
|
||||||
public var ingredientsFromPalmOilTags: [String]?
|
|
||||||
public var ingredientsFromPalmOilN: Float?
|
|
||||||
public var ingredientsHierarchy: [String]?
|
|
||||||
public var ingredientsIdsDebug: [String]?
|
|
||||||
public var ingredientsN: Float?
|
|
||||||
public var ingredientsNTags: [String]?
|
|
||||||
public var ingredientsOriginalTags: [String]?
|
|
||||||
public var ingredientsTags: [String]?
|
|
||||||
public var ingredientsText: String?
|
|
||||||
public var ingredientsTextDebug: String?
|
|
||||||
public var ingredientsTextWithAllergens: String?
|
|
||||||
public var ingredientsThatMayBeFromPalmOilN: Float?
|
|
||||||
public var ingredientsThatMayBeFromPalmOilTags: [String]?
|
|
||||||
public var interfaceVersionCreated: String?
|
|
||||||
public var interfaceVersionModified: String?
|
|
||||||
public var keywords: [String]?
|
|
||||||
public var knownIngredientsN: Float?
|
|
||||||
public var labels: String?
|
|
||||||
public var labelsHierarchy: [String]?
|
|
||||||
public var labelsLc: String?
|
|
||||||
public var labelsPrevHierarchy: [String]?
|
|
||||||
public var labelsPrevTags: [String]?
|
|
||||||
public var labelsTags: [String]?
|
|
||||||
public var labelsDebugTags: [String]?
|
|
||||||
public var lang: String?
|
|
||||||
public var langDebugTags: [String]?
|
|
||||||
public var languagesHierarchy: [String]?
|
|
||||||
public var languagesTags: [String]?
|
|
||||||
public var lastEditDatesTags: [String]?
|
|
||||||
public var lastEditor: String?
|
|
||||||
public var lastImageDatesTags: [String]?
|
|
||||||
public var lastImageT: Float?
|
|
||||||
public var lastModifiedBy: String?
|
|
||||||
public var lastModifiedT: Float?
|
|
||||||
public var lc: String?
|
|
||||||
public var link: String?
|
|
||||||
public var linkDebugTags: [String]?
|
|
||||||
public var manufacturingPlaces: String?
|
|
||||||
public var manufacturingPlacesDebugTags: [String]?
|
|
||||||
public var manufacturingPlacesTags: [String]?
|
|
||||||
public var maxImgid: String?
|
|
||||||
public var mineralsPrevTags: [String]?
|
|
||||||
public var mineralsTags: [String]?
|
|
||||||
public var miscTags: [String]?
|
|
||||||
public var netWeightUnit: String?
|
|
||||||
public var netWeightValue: String?
|
|
||||||
public var nutritionDataPer: String?
|
|
||||||
public var nutritionScoreWarningNoFruitsVegetablesNuts: Float?
|
|
||||||
public var nutriscoreGrade: String?
|
|
||||||
public var noNutritionData: String?
|
|
||||||
public var novaGroup: Float?
|
|
||||||
public var novaGroups: String?
|
|
||||||
public var novaGroupDebug: String?
|
|
||||||
public var novaGroupTags: [String]?
|
|
||||||
public var novaGroupsTags: [String]?
|
|
||||||
public var nucleotidesPrevTags: [String]?
|
|
||||||
public var nucleotidesTags: [String]?
|
|
||||||
public var nutrientLevelsTags: [String]?
|
|
||||||
public var nutritionData: String?
|
|
||||||
public var nutritionDataPerDebugTags: [String]?
|
|
||||||
public var nutritionDataPrepared: String?
|
|
||||||
public var nutritionDataPreparedPer: String?
|
|
||||||
public var nutritionGrades: String?
|
|
||||||
public var nutritionScoreBeverage: Float?
|
|
||||||
public var nutritionScoreDebug: String?
|
|
||||||
public var nutritionScoreWarningNoFiber: Float?
|
|
||||||
public var nutritionGradesTags: [String]?
|
|
||||||
public var origins: String?
|
|
||||||
public var originsDebugTags: [String]?
|
|
||||||
public var originsTags: [String]?
|
|
||||||
public var otherInformation: String?
|
|
||||||
public var otherNutritionalSubstancesTags: [String]?
|
|
||||||
public var packaging: String?
|
|
||||||
public var packagingDebugTags: [String]?
|
|
||||||
public var packagingTags: [String]?
|
|
||||||
public var photographersTags: [String]?
|
|
||||||
public var pnnsGroups1: String?
|
|
||||||
public var pnnsGroups2: String?
|
|
||||||
public var pnnsGroups1Tags: [String]?
|
|
||||||
public var pnnsGroups2Tags: [String]?
|
|
||||||
public var popularityKey: Float?
|
|
||||||
public var producerVersionId: String?
|
|
||||||
public var productName: String?
|
|
||||||
public var productQuantity: Float?
|
|
||||||
public var purchasePlaces: String?
|
|
||||||
public var purchasePlacesDebugTags: [String]?
|
|
||||||
public var purchasePlacesTags: [String]?
|
|
||||||
public var qualityTags: [String]?
|
|
||||||
public var quantity: String?
|
|
||||||
public var quantityDebugTags: [String]?
|
|
||||||
public var recyclingInstructionsToDiscard: String?
|
|
||||||
public var rev: Float?
|
|
||||||
public var servingQuantity: String?
|
|
||||||
public var servingSize: String?
|
|
||||||
public var servingSizeDebugTags: [String]?
|
|
||||||
public var sortkey: Float?
|
|
||||||
public var states: String?
|
|
||||||
public var statesHierarchy: [String]?
|
|
||||||
public var statesTags: [String]?
|
|
||||||
public var stores: String?
|
|
||||||
public var storesDebugTags: [String]?
|
|
||||||
public var storesTags: [String]?
|
|
||||||
public var traces: String?
|
|
||||||
public var tracesFromIngredients: String?
|
|
||||||
public var tracesHierarchy: [String]?
|
|
||||||
public var tracesDebugTags: [String]?
|
|
||||||
public var tracesFromUser: String?
|
|
||||||
public var tracesLc: String?
|
|
||||||
public var tracesTags: [String]?
|
|
||||||
public var unknownIngredientsN: Float?
|
|
||||||
public var unknownNutrientsTags: [String]?
|
|
||||||
public var updateKey: String?
|
|
||||||
public var vitaminsPrevTags: [String]?
|
|
||||||
public var vitaminsTags: [String]?
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
|
||||||
// case images
|
|
||||||
case ingredients
|
|
||||||
case languagesCodes = "languages_codes"
|
|
||||||
case nutrientLevels = "nutrient_levels"
|
|
||||||
case nutriments
|
|
||||||
case selectedImages = "selected_images"
|
|
||||||
case sources
|
|
||||||
case additivesN = "additives_n"
|
|
||||||
case additivesOldN = "additives_old_n"
|
|
||||||
case additivesOriginalTags = "additives_original_tags"
|
|
||||||
case additivesOldTags = "additives_old_tags"
|
|
||||||
case additivesPrevOriginalTags = "additives_prev_original_tags"
|
|
||||||
case additivesDebugTags = "additives_debug_tags"
|
|
||||||
case additivesTags = "additives_tags"
|
|
||||||
case allergens
|
|
||||||
case allergensFromIngredients = "allergens_from_ingredients"
|
|
||||||
case allergensFromUser = "allergens_from_user"
|
|
||||||
case allergensHierarchy = "allergens_hierarchy"
|
|
||||||
case allergensLc = "allergens_lc"
|
|
||||||
case allergensTags = "allergens_tags"
|
|
||||||
case aminoAcidsPrevTags = "amino_acids_prev_tags"
|
|
||||||
case aminoAcidsTags = "amino_acids_tags"
|
|
||||||
case brands
|
|
||||||
case brandsDebugTags = "brands_debug_tags"
|
|
||||||
case brandsTags = "brands_tags"
|
|
||||||
case carbonFootprintPercentOfKnownIngredients = "carbon_footprint_percent_of_known_ingredients"
|
|
||||||
case carbonFootprintFromKnownIngredientsDebug = "carbon_footprint_from_known_ingredients_debug"
|
|
||||||
case categories
|
|
||||||
case categoriesHierarchy = "categories_hierarchy"
|
|
||||||
case categoriesLc = "categories_lc"
|
|
||||||
case categoriesPropertiesTags = "categories_properties_tags"
|
|
||||||
case categoriesTags = "categories_tags"
|
|
||||||
case checkersTags = "checkers_tags"
|
|
||||||
case citiesTags = "cities_tags"
|
|
||||||
case code
|
|
||||||
case codesTags = "codes_tags"
|
|
||||||
case comparedToCategory = "compared_to_category"
|
|
||||||
case complete
|
|
||||||
case completedT = "completed_t"
|
|
||||||
case completeness
|
|
||||||
case conservationConditions = "conservation_conditions"
|
|
||||||
case countries
|
|
||||||
case countriesHierarchy = "countries_hierarchy"
|
|
||||||
case countriesLc = "countries_lc"
|
|
||||||
case countriesDebugTags = "countries_debug_tags"
|
|
||||||
case countriesTags = "countries_tags"
|
|
||||||
case correctorsTags = "correctors_tags"
|
|
||||||
case createdT = "created_t"
|
|
||||||
case creator
|
|
||||||
case dataQualityBugsTags = "data_quality_bugs_tags"
|
|
||||||
case dataQualityErrorsTags = "data_quality_errors_tags"
|
|
||||||
case dataQualityInfoTags = "data_quality_info_tags"
|
|
||||||
case dataQualityTags = "data_quality_tags"
|
|
||||||
case dataQualityWarningsTags = "data_quality_warnings_tags"
|
|
||||||
case dataSources = "data_sources"
|
|
||||||
case dataSourcesTags = "data_sources_tags"
|
|
||||||
case debugParamSortedLangs = "debug_param_sorted_langs"
|
|
||||||
case editorsTags = "editors_tags"
|
|
||||||
case embCodes = "emb_codes"
|
|
||||||
case embCodesDebugTags = "emb_codes_debug_tags"
|
|
||||||
case embCodesOrig = "emb_codes_orig"
|
|
||||||
case embCodesTags = "emb_codes_tags"
|
|
||||||
case entryDatesTags = "entry_dates_tags"
|
|
||||||
case expirationDate = "expiration_date"
|
|
||||||
case expirationDateDebugTags = "expiration_date_debug_tags"
|
|
||||||
case fruitsVegetablesNuts100GEstimate = "fruits-vegetables-nuts_100g_estimate"
|
|
||||||
case genericName
|
|
||||||
case id
|
|
||||||
case imageFrontSmallUrl = "image_front_small_url"
|
|
||||||
case imageFrontThumbUrl = "image_front_thumb_url"
|
|
||||||
case imageFrontUrl = "image_front_url"
|
|
||||||
case imageIngredientsUrl = "image_ingredients_url"
|
|
||||||
case imageIngredientsSmallUrl = "image_ingredients_small_url"
|
|
||||||
case imageIngredientsThumbUrl = "image_ingredients_thumb_url"
|
|
||||||
case imageNutritionSmallUrl = "image_nutrition_small_url"
|
|
||||||
case imageNutritionThumbUrl = "image_nutrition_thumb_url"
|
|
||||||
case imageNutritionUrl = "image_nutrition_url"
|
|
||||||
case imageSmallUrl = "image_small_url"
|
|
||||||
case imageThumbUrl = "image_thumb_url"
|
|
||||||
case imageUrl = "image_url"
|
|
||||||
case informersTags = "informers_tags"
|
|
||||||
case ingredientsAnalysisTags = "ingredients_analysis_tags"
|
|
||||||
case ingredientsDebug = "ingredients_debug"
|
|
||||||
case ingredientsFromOrThatMayBeFromPalmOilN = "ingredients_from_or_that_may_be_from_palm_oil_n"
|
|
||||||
case ingredientsFromPalmOilTags = "ingredients_from_palm_oil_tags"
|
|
||||||
case ingredientsFromPalmOilN = "ingredients_from_palm_oil_n"
|
|
||||||
case ingredientsHierarchy = "ingredients_hierarchy"
|
|
||||||
case ingredientsIdsDebug = "ingredients_ids_debug"
|
|
||||||
case ingredientsN = "ingredients_n"
|
|
||||||
case ingredientsNTags = "ingredients_n_tags"
|
|
||||||
case ingredientsOriginalTags = "ingredients_original_tags"
|
|
||||||
case ingredientsTags = "ingredients_tags"
|
|
||||||
case ingredientsText = "ingredients_text"
|
|
||||||
case ingredientsTextDebug = "ingredients_text_debug"
|
|
||||||
case ingredientsTextWithAllergens = "ingredients_text_with_allergens"
|
|
||||||
case ingredientsThatMayBeFromPalmOilN = "ingredients_that_may_be_from_palm_oil_n"
|
|
||||||
case ingredientsThatMayBeFromPalmOilTags = "ingredients_that_may_be_from_palm_oil_tags"
|
|
||||||
case interfaceVersionCreated = "interface_version_created"
|
|
||||||
case interfaceVersionModified = "interface_version_modified"
|
|
||||||
case keywords
|
|
||||||
case knownIngredientsN = "known_ingredients_n"
|
|
||||||
case labels
|
|
||||||
case labelsHierarchy = "labels_hierarchy"
|
|
||||||
case labelsLc = "labels_lc"
|
|
||||||
case labelsPrevHierarchy = "labels_prev_hierarchy"
|
|
||||||
case labelsPrevTags = "labels_prev_tags"
|
|
||||||
case labelsTags = "labels_tags"
|
|
||||||
case labelsDebugTags = "labels_debug_tags"
|
|
||||||
case lang
|
|
||||||
case langDebugTags = "lang_debug_tags"
|
|
||||||
case languagesHierarchy = "languages_hierarchy"
|
|
||||||
case languagesTags = "languages_tags"
|
|
||||||
case lastEditDatesTags = "last_edit_dates_tags"
|
|
||||||
case lastEditor = "last_editor"
|
|
||||||
case lastImageDatesTags = "last_image_dates_tags"
|
|
||||||
case lastImageT = "last_image_t"
|
|
||||||
case lastModifiedBy = "last_modified_by"
|
|
||||||
case lastModifiedT = "last_modified_t"
|
|
||||||
case lc
|
|
||||||
case link
|
|
||||||
case linkDebugTags = "link_debug_tags"
|
|
||||||
case manufacturingPlaces = "manufacturing_places"
|
|
||||||
case manufacturingPlacesDebugTags = "manufacturing_places_debug_tags"
|
|
||||||
case manufacturingPlacesTags = "manufacturing_places_tags"
|
|
||||||
case maxImgid = "max_imgid"
|
|
||||||
case mineralsPrevTags = "minerals_prev_tags"
|
|
||||||
case mineralsTags = "minerals_tags"
|
|
||||||
case miscTags = "misc_tags"
|
|
||||||
case netWeightUnit = "net_weight_unit"
|
|
||||||
case netWeightValue = "net_weight_value"
|
|
||||||
case nutritionDataPer = "nutrition_data_per"
|
|
||||||
case nutritionScoreWarningNoFruitsVegetablesNuts = "nutrition_score_warning_no_fruits_vegetables_nuts"
|
|
||||||
case nutriscoreGrade = "nutriscore_grade"
|
|
||||||
case noNutritionData = "no_nutrition_data"
|
|
||||||
case novaGroup = "nova_group"
|
|
||||||
case novaGroups = "nova_groups"
|
|
||||||
case novaGroupDebug = "nova_group_debug"
|
|
||||||
case novaGroupTags = "nova_group_tags"
|
|
||||||
case novaGroupsTags = "nova_groups_tags"
|
|
||||||
case nucleotidesPrevTags = "nucleotides_prev_tags"
|
|
||||||
case nucleotidesTags = "nucleotides_tags"
|
|
||||||
case nutrientLevelsTags = "nutrient_levels_tags"
|
|
||||||
case nutritionData = "nutrition_data"
|
|
||||||
case nutritionDataPerDebugTags = "nutrition_data_per_debug_tags"
|
|
||||||
case nutritionDataPrepared = "nutrition_data_prepared"
|
|
||||||
case nutritionDataPreparedPer = "nutrition_data_prepared_per"
|
|
||||||
case nutritionGrades = "nutrition_grades"
|
|
||||||
case nutritionScoreBeverage = "nutrition_score_beverage"
|
|
||||||
case nutritionScoreDebug = "nutrition_score_debug"
|
|
||||||
case nutritionScoreWarningNoFiber = "nutrition_score_warning_no_fiber"
|
|
||||||
case nutritionGradesTags = "nutrition_grades_tags"
|
|
||||||
case origins
|
|
||||||
case originsDebugTags = "origins_debug_tags"
|
|
||||||
case originsTags = "origins_tags"
|
|
||||||
case otherInformation = "other_information"
|
|
||||||
case otherNutritionalSubstancesTags = "other_nutritional_substances_tags"
|
|
||||||
case packaging
|
|
||||||
case packagingDebugTags = "packaging_debug_tags"
|
|
||||||
case packagingTags = "packaging_tags"
|
|
||||||
case photographersTags = "photographers_tags"
|
|
||||||
case pnnsGroups1 = "pnns_groups_1"
|
|
||||||
case pnnsGroups2 = "pnns_groups_2"
|
|
||||||
case pnnsGroups1Tags = "pnns_groups_1_tags"
|
|
||||||
case pnnsGroups2Tags = "pnns_groups_2_tags"
|
|
||||||
case popularityKey = "popularity_key"
|
|
||||||
case producerVersionId = "producer_version_id"
|
|
||||||
case productName = "product_name"
|
|
||||||
case productQuantity = "product_quantity"
|
|
||||||
case purchasePlaces = "purchase_places"
|
|
||||||
case purchasePlacesDebugTags = "purchase_places_debug_tags"
|
|
||||||
case purchasePlacesTags = "purchase_places_tags"
|
|
||||||
case qualityTags = "quality_tags"
|
|
||||||
case quantity
|
|
||||||
case quantityDebugTags = "quantity_debug_tags"
|
|
||||||
case recyclingInstructionsToDiscard = "recycling_instructions_to_discard"
|
|
||||||
case rev
|
|
||||||
case servingQuantity = "serving_quantity"
|
|
||||||
case servingSize = "serving_size"
|
|
||||||
case servingSizeDebugTags = "serving_size_debug_tags"
|
|
||||||
case sortkey
|
|
||||||
case states
|
|
||||||
case statesHierarchy = "states_hierarchy"
|
|
||||||
case statesTags = "states_tags"
|
|
||||||
case stores
|
|
||||||
case storesDebugTags = "stores_debug_tags"
|
|
||||||
case storesTags = "stores_tags"
|
|
||||||
case traces
|
|
||||||
case tracesFromIngredients = "traces_from_ingredients"
|
|
||||||
case tracesHierarchy = "traces_hierarchy"
|
|
||||||
case tracesDebugTags = "traces_debug_tags"
|
|
||||||
case tracesFromUser = "traces_from_user"
|
|
||||||
case tracesLc = "traces_lc"
|
|
||||||
case tracesTags = "traces_tags"
|
|
||||||
case unknownIngredientsN = "unknown_ingredients_n"
|
|
||||||
case unknownNutrientsTags = "unknown_nutrients_tags"
|
|
||||||
case updateKey = "update_key"
|
|
||||||
case vitaminsPrevTags = "vitamins_prev_tags"
|
|
||||||
case vitaminsTags = "vitamins_tags"
|
|
||||||
}
|
|
||||||
|
|
||||||
public required init(from decoder: Decoder) throws {
|
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
||||||
ingredients = try container.decodeIfPresent([Ingredient].self, forKey: .ingredients)
|
|
||||||
languagesCodes = try container.decodeIfPresent(LanguagesCodes.self, forKey: .languagesCodes)
|
|
||||||
nutrientLevels = try container.decodeIfPresent(NutrientLevels.self, forKey: .nutrientLevels)
|
|
||||||
nutriments = try container.decodeIfPresent(Nutriments.self, forKey: .nutriments) ?? Nutriments()
|
|
||||||
selectedImages = try container.decodeIfPresent(SelectedImages.self, forKey: .selectedImages)
|
|
||||||
sources = try container.decodeIfPresent([Source].self, forKey: .sources)
|
|
||||||
additivesN = try container.decodeIfPresent(Float.self, forKey: .additivesN)
|
|
||||||
additivesOldN = try container.decodeIfPresent(Float.self, forKey: .additivesOldN)
|
|
||||||
additivesOriginalTags = try container.decodeIfPresent([String].self, forKey: .additivesOriginalTags)
|
|
||||||
additivesOldTags = try container.decodeIfPresent([String].self, forKey: .additivesOldTags)
|
|
||||||
additivesPrevOriginalTags = try container.decodeIfPresent([String].self, forKey: .additivesPrevOriginalTags)
|
|
||||||
additivesDebugTags = try container.decodeIfPresent([String].self, forKey: .additivesDebugTags)
|
|
||||||
additivesTags = try container.decodeIfPresent([String].self, forKey: .additivesTags)
|
|
||||||
allergens = try container.decodeIfPresent(String.self, forKey: .allergens)
|
|
||||||
allergensFromIngredients = try container.decodeIfPresent(String.self, forKey: .allergensFromIngredients)
|
|
||||||
allergensFromUser = try container.decodeIfPresent(String.self, forKey: .allergensFromUser)
|
|
||||||
allergensHierarchy = try container.decodeIfPresent([String].self, forKey: .allergensHierarchy)
|
|
||||||
allergensLc = try container.decodeIfPresent(String.self, forKey: .allergensLc)
|
|
||||||
allergensTags = try container.decodeIfPresent([String].self, forKey: .allergensTags)
|
|
||||||
aminoAcidsPrevTags = try container.decodeIfPresent([String].self, forKey: .aminoAcidsPrevTags)
|
|
||||||
aminoAcidsTags = try container.decodeIfPresent([String].self, forKey: .aminoAcidsTags)
|
|
||||||
brands = try container.decodeIfPresent(String.self, forKey: .brands)
|
|
||||||
brandsDebugTags = try container.decodeIfPresent([String].self, forKey: .brandsDebugTags)
|
|
||||||
brandsTags = try container.decodeIfPresent([String].self, forKey: .brandsTags)
|
|
||||||
carbonFootprintPercentOfKnownIngredients = try container.decodeIfPresent(Float.self, forKey: .carbonFootprintPercentOfKnownIngredients)
|
|
||||||
carbonFootprintFromKnownIngredientsDebug = try container.decodeIfPresent(String.self, forKey: .carbonFootprintFromKnownIngredientsDebug)
|
|
||||||
categories = try container.decodeIfPresent(String.self, forKey: .categories)
|
|
||||||
categoriesHierarchy = try container.decodeIfPresent([String].self, forKey: .categoriesHierarchy)
|
|
||||||
categoriesLc = try container.decodeIfPresent(String.self, forKey: .categoriesLc)
|
|
||||||
categoriesPropertiesTags = try container.decodeIfPresent([String].self, forKey: .categoriesPropertiesTags)
|
|
||||||
categoriesTags = try container.decodeIfPresent([String].self, forKey: .categoriesTags)
|
|
||||||
checkersTags = try container.decodeIfPresent([String].self, forKey: .checkersTags)
|
|
||||||
citiesTags = try container.decodeIfPresent([String].self, forKey: .citiesTags)
|
|
||||||
code = try container.decodeIfPresent(String.self, forKey: .code)
|
|
||||||
codesTags = try container.decodeIfPresent([String].self, forKey: .codesTags)
|
|
||||||
comparedToCategory = try container.decodeIfPresent(String.self, forKey: .comparedToCategory)
|
|
||||||
complete = try container.decodeIfPresent(Float.self, forKey: .complete)
|
|
||||||
completedT = try container.decodeIfPresent(Float.self, forKey: .completedT)
|
|
||||||
completeness = try container.decodeIfPresent(Double.self, forKey: .completeness)
|
|
||||||
conservationConditions = try container.decodeIfPresent(String.self, forKey: .conservationConditions)
|
|
||||||
countries = try container.decodeIfPresent(String.self, forKey: .countries)
|
|
||||||
countriesHierarchy = try container.decodeIfPresent([String].self, forKey: .countriesHierarchy)
|
|
||||||
countriesLc = try container.decodeIfPresent(String.self, forKey: .countriesLc)
|
|
||||||
countriesDebugTags = try container.decodeIfPresent([String].self, forKey: .countriesDebugTags)
|
|
||||||
countriesTags = try container.decodeIfPresent([String].self, forKey: .countriesTags)
|
|
||||||
correctorsTags = try container.decodeIfPresent([String].self, forKey: .correctorsTags)
|
|
||||||
createdT = try container.decodeIfPresent(Float.self, forKey: .createdT)
|
|
||||||
creator = try container.decodeIfPresent(String.self, forKey: .creator)
|
|
||||||
dataQualityBugsTags = try container.decodeIfPresent([String].self, forKey: .dataQualityBugsTags)
|
|
||||||
dataQualityErrorsTags = try container.decodeIfPresent([String].self, forKey: .dataQualityErrorsTags)
|
|
||||||
dataQualityInfoTags = try container.decodeIfPresent([String].self, forKey: .dataQualityInfoTags)
|
|
||||||
dataQualityTags = try container.decodeIfPresent([String].self, forKey: .dataQualityTags)
|
|
||||||
dataQualityWarningsTags = try container.decodeIfPresent([String].self, forKey: .dataQualityWarningsTags)
|
|
||||||
dataSources = try container.decodeIfPresent(String.self, forKey: .dataSources)
|
|
||||||
dataSourcesTags = try container.decodeIfPresent([String].self, forKey: .dataSourcesTags)
|
|
||||||
debugParamSortedLangs = try container.decodeIfPresent([String].self, forKey: .debugParamSortedLangs)
|
|
||||||
editorsTags = try container.decodeIfPresent([String].self, forKey: .editorsTags)
|
|
||||||
embCodes = try container.decodeIfPresent(String.self, forKey: .embCodes)
|
|
||||||
embCodesDebugTags = try container.decodeIfPresent([String].self, forKey: .embCodesDebugTags)
|
|
||||||
embCodesOrig = try container.decodeIfPresent(String.self, forKey: .embCodesOrig)
|
|
||||||
embCodesTags = try container.decodeIfPresent([String].self, forKey: .embCodesTags)
|
|
||||||
entryDatesTags = try container.decodeIfPresent([String].self, forKey: .entryDatesTags)
|
|
||||||
expirationDate = try container.decodeIfPresent(String.self, forKey: .expirationDate)
|
|
||||||
expirationDateDebugTags = try container.decodeIfPresent([String].self, forKey: .expirationDateDebugTags)
|
|
||||||
fruitsVegetablesNuts100GEstimate = try container.decodeIfPresent(Float.self, forKey: .fruitsVegetablesNuts100GEstimate)
|
|
||||||
genericName = try container.decodeIfPresent(String.self, forKey: .genericName)
|
|
||||||
id = try container.decodeIfPresent(String.self, forKey: .id)
|
|
||||||
imageFrontSmallUrl = try container.decodeIfPresent(String.self, forKey: .imageFrontSmallUrl)
|
|
||||||
imageFrontThumbUrl = try container.decodeIfPresent(String.self, forKey: .imageFrontThumbUrl)
|
|
||||||
imageFrontUrl = try container.decodeIfPresent(String.self, forKey: .imageFrontUrl)
|
|
||||||
imageIngredientsUrl = try container.decodeIfPresent(String.self, forKey: .imageIngredientsUrl)
|
|
||||||
imageIngredientsSmallUrl = try container.decodeIfPresent(String.self, forKey: .imageIngredientsSmallUrl)
|
|
||||||
imageIngredientsThumbUrl = try container.decodeIfPresent(String.self, forKey: .imageIngredientsThumbUrl)
|
|
||||||
imageNutritionSmallUrl = try container.decodeIfPresent(String.self, forKey: .imageNutritionSmallUrl)
|
|
||||||
imageNutritionThumbUrl = try container.decodeIfPresent(String.self, forKey: .imageNutritionThumbUrl)
|
|
||||||
imageNutritionUrl = try container.decodeIfPresent(String.self, forKey: .imageNutritionUrl)
|
|
||||||
imageSmallUrl = try container.decodeIfPresent(String.self, forKey: .imageSmallUrl)
|
|
||||||
imageThumbUrl = try container.decodeIfPresent(String.self, forKey: .imageThumbUrl)
|
|
||||||
imageUrl = try container.decodeIfPresent(String.self, forKey: .imageUrl)
|
|
||||||
informersTags = try container.decodeIfPresent([String].self, forKey: .informersTags)
|
|
||||||
ingredientsAnalysisTags = try container.decodeIfPresent([String].self, forKey: .ingredientsAnalysisTags)
|
|
||||||
ingredientsDebug = try container.decodeIfPresent([String?].self, forKey: .ingredientsDebug)
|
|
||||||
ingredientsFromOrThatMayBeFromPalmOilN = try container.decodeIfPresent(Float.self, forKey: .ingredientsFromOrThatMayBeFromPalmOilN)
|
|
||||||
ingredientsFromPalmOilTags = try container.decodeIfPresent([String].self, forKey: .ingredientsFromPalmOilTags)
|
|
||||||
ingredientsFromPalmOilN = try container.decodeIfPresent(Float.self, forKey: .ingredientsFromPalmOilN)
|
|
||||||
ingredientsHierarchy = try container.decodeIfPresent([String].self, forKey: .ingredientsHierarchy)
|
|
||||||
ingredientsIdsDebug = try container.decodeIfPresent([String].self, forKey: .ingredientsIdsDebug)
|
|
||||||
if container.contains(.ingredientsN) {
|
|
||||||
if try container.decodeNil(forKey: .ingredientsN) {
|
|
||||||
ingredientsN = nil
|
|
||||||
} else {
|
|
||||||
if let intValue = try? container.decode(Float.self, forKey: .ingredientsN) {
|
|
||||||
ingredientsN = intValue
|
|
||||||
} else if let stringValue = try? container.decode(String.self, forKey: .ingredientsN) {
|
|
||||||
ingredientsN = Float(stringValue)
|
|
||||||
}else {
|
|
||||||
// If decoding as both Float and String fails, handle the error accordingly
|
|
||||||
throw DecodingError.dataCorruptedError(
|
|
||||||
forKey: .ingredientsN,
|
|
||||||
in: container,
|
|
||||||
debugDescription: "Unable to decode ingredientsN"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ingredientsN = nil
|
|
||||||
}
|
|
||||||
ingredientsNTags = try container.decodeIfPresent([String].self, forKey: .ingredientsNTags)
|
|
||||||
ingredientsOriginalTags = try container.decodeIfPresent([String].self, forKey: .ingredientsOriginalTags)
|
|
||||||
ingredientsTags = try container.decodeIfPresent([String].self, forKey: .ingredientsTags)
|
|
||||||
ingredientsText = try container.decodeIfPresent(String.self, forKey: .ingredientsText)
|
|
||||||
ingredientsTextDebug = try container.decodeIfPresent(String.self, forKey: .ingredientsTextDebug)
|
|
||||||
ingredientsTextWithAllergens = try container.decodeIfPresent(String.self, forKey: .ingredientsTextWithAllergens)
|
|
||||||
ingredientsThatMayBeFromPalmOilN = try container.decodeIfPresent(Float.self, forKey: .ingredientsThatMayBeFromPalmOilN)
|
|
||||||
ingredientsThatMayBeFromPalmOilTags = try container.decodeIfPresent([String].self, forKey: .ingredientsThatMayBeFromPalmOilTags)
|
|
||||||
interfaceVersionCreated = try container.decodeIfPresent(String.self, forKey: .interfaceVersionCreated)
|
|
||||||
interfaceVersionModified = try container.decodeIfPresent(String.self, forKey: .interfaceVersionModified)
|
|
||||||
keywords = try container.decodeIfPresent([String].self, forKey: .keywords)
|
|
||||||
knownIngredientsN = try container.decodeIfPresent(Float.self, forKey: .knownIngredientsN)
|
|
||||||
labels = try container.decodeIfPresent(String.self, forKey: .labels)
|
|
||||||
labelsHierarchy = try container.decodeIfPresent([String].self, forKey: .labelsHierarchy)
|
|
||||||
labelsLc = try container.decodeIfPresent(String.self, forKey: .labelsLc)
|
|
||||||
labelsPrevHierarchy = try container.decodeIfPresent([String].self, forKey: .labelsPrevHierarchy)
|
|
||||||
labelsPrevTags = try container.decodeIfPresent([String].self, forKey: .labelsPrevTags)
|
|
||||||
labelsTags = try container.decodeIfPresent([String].self, forKey: .labelsTags)
|
|
||||||
labelsDebugTags = try container.decodeIfPresent([String].self, forKey: .labelsDebugTags)
|
|
||||||
lang = try container.decodeIfPresent(String.self, forKey: .lang)
|
|
||||||
langDebugTags = try container.decodeIfPresent([String].self, forKey: .langDebugTags)
|
|
||||||
languagesHierarchy = try container.decodeIfPresent([String].self, forKey: .languagesHierarchy)
|
|
||||||
languagesTags = try container.decodeIfPresent([String].self, forKey: .languagesTags)
|
|
||||||
lastEditDatesTags = try container.decodeIfPresent([String].self, forKey: .lastEditDatesTags)
|
|
||||||
lastEditor = try container.decodeIfPresent(String.self, forKey: .lastEditor)
|
|
||||||
lastImageDatesTags = try container.decodeIfPresent([String].self, forKey: .lastImageDatesTags)
|
|
||||||
lastImageT = try container.decodeIfPresent(Float.self, forKey: .lastImageT)
|
|
||||||
lastModifiedBy = try container.decodeIfPresent(String.self, forKey: .lastModifiedBy)
|
|
||||||
if container.contains(.lastModifiedT) {
|
|
||||||
if try container.decodeNil(forKey: .maxImgid) {
|
|
||||||
lastModifiedT = nil
|
|
||||||
} else {
|
|
||||||
if let floatValue = try? container.decode(Float.self, forKey: .lastModifiedT) {
|
|
||||||
lastModifiedT = floatValue
|
|
||||||
} else if let stringValue = try? container.decode(String.self, forKey: .lastModifiedT) {
|
|
||||||
lastModifiedT = Float(stringValue)
|
|
||||||
}else {
|
|
||||||
// If decoding as both Float and String fails, handle the error accordingly
|
|
||||||
throw DecodingError.dataCorruptedError(
|
|
||||||
forKey: .lastModifiedT,
|
|
||||||
in: container,
|
|
||||||
debugDescription: "Unable to decode lastModifiedT"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lastModifiedT = nil
|
|
||||||
}
|
|
||||||
lc = try container.decodeIfPresent(String.self, forKey: .lc)
|
|
||||||
link = try container.decodeIfPresent(String.self, forKey: .link)
|
|
||||||
linkDebugTags = try container.decodeIfPresent([String].self, forKey: .linkDebugTags)
|
|
||||||
manufacturingPlaces = try container.decodeIfPresent(String.self, forKey: .manufacturingPlaces)
|
|
||||||
manufacturingPlacesDebugTags = try container.decodeIfPresent([String].self, forKey: .manufacturingPlacesDebugTags)
|
|
||||||
manufacturingPlacesTags = try container.decodeIfPresent([String].self, forKey: .manufacturingPlacesTags)
|
|
||||||
if container.contains(.maxImgid) {
|
|
||||||
if try container.decodeNil(forKey: .maxImgid) {
|
|
||||||
maxImgid = nil
|
|
||||||
} else {
|
|
||||||
if let floatValue = try? container.decode(Float.self, forKey: .maxImgid) {
|
|
||||||
maxImgid = "\(floatValue)"
|
|
||||||
} else if let stringValue = try? container.decode(String.self, forKey: .maxImgid) {
|
|
||||||
maxImgid = stringValue
|
|
||||||
}else {
|
|
||||||
// If decoding as both Float and String fails, handle the error accordingly
|
|
||||||
throw DecodingError.dataCorruptedError(
|
|
||||||
forKey: .maxImgid,
|
|
||||||
in: container,
|
|
||||||
debugDescription: "Unable to decode maxImgid"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
maxImgid = nil
|
|
||||||
}
|
|
||||||
mineralsPrevTags = try container.decodeIfPresent([String].self, forKey: .mineralsPrevTags)
|
|
||||||
mineralsTags = try container.decodeIfPresent([String].self, forKey: .mineralsTags)
|
|
||||||
miscTags = try container.decodeIfPresent([String].self, forKey: .miscTags)
|
|
||||||
netWeightUnit = try container.decodeIfPresent(String.self, forKey: .netWeightUnit)
|
|
||||||
netWeightValue = try container.decodeIfPresent(String.self, forKey: .netWeightValue)
|
|
||||||
nutritionDataPer = try container.decodeIfPresent(String.self, forKey: .nutritionDataPer)
|
|
||||||
nutritionScoreWarningNoFruitsVegetablesNuts = try container.decodeIfPresent(Float.self, forKey: .nutritionScoreWarningNoFruitsVegetablesNuts)
|
|
||||||
noNutritionData = try container.decodeIfPresent(String.self, forKey: .noNutritionData)
|
|
||||||
novaGroup = try container.decodeIfPresent(Float.self, forKey: .novaGroup)
|
|
||||||
novaGroups = try container.decodeIfPresent(String.self, forKey: .novaGroups)
|
|
||||||
novaGroupDebug = try container.decodeIfPresent(String.self, forKey: .novaGroupDebug)
|
|
||||||
novaGroupTags = try container.decodeIfPresent([String].self, forKey: .novaGroupTags)
|
|
||||||
novaGroupsTags = try container.decodeIfPresent([String].self, forKey: .novaGroupsTags)
|
|
||||||
nucleotidesTags = try container.decodeIfPresent([String].self, forKey: .nucleotidesTags)
|
|
||||||
nutrientLevelsTags = try container.decodeIfPresent([String].self, forKey: .nutrientLevelsTags)
|
|
||||||
nutritionData = try container.decodeIfPresent(String.self, forKey: .nutritionData)
|
|
||||||
nutriscoreGrade = try container.decodeIfPresent(String.self, forKey: .nutriscoreGrade)
|
|
||||||
nutritionDataPerDebugTags = try container.decodeIfPresent([String].self, forKey: .nutritionDataPerDebugTags)
|
|
||||||
nutritionDataPrepared = try container.decodeIfPresent(String.self, forKey: .nutritionDataPrepared)
|
|
||||||
nutritionDataPreparedPer = try container.decodeIfPresent(String.self, forKey: .nutritionDataPreparedPer)
|
|
||||||
nutritionGrades = try container.decodeIfPresent(String.self, forKey: .nutritionGrades)
|
|
||||||
nutritionScoreBeverage = try container.decodeIfPresent(Float.self, forKey: .nutritionScoreBeverage)
|
|
||||||
nutritionScoreDebug = try container.decodeIfPresent(String.self, forKey: .nutritionScoreDebug)
|
|
||||||
nutritionScoreWarningNoFiber = try container.decodeIfPresent(Float.self, forKey: .nutritionScoreWarningNoFiber)
|
|
||||||
nutritionGradesTags = try container.decodeIfPresent([String].self, forKey: .nutritionGradesTags)
|
|
||||||
origins = try container.decodeIfPresent(String.self, forKey: .origins)
|
|
||||||
originsDebugTags = try container.decodeIfPresent([String].self, forKey: .originsDebugTags)
|
|
||||||
originsTags = try container.decodeIfPresent([String].self, forKey: .originsTags)
|
|
||||||
otherInformation = try container.decodeIfPresent(String.self, forKey: .otherInformation)
|
|
||||||
otherNutritionalSubstancesTags = try container.decodeIfPresent([String].self, forKey: .otherNutritionalSubstancesTags)
|
|
||||||
packaging = try container.decodeIfPresent(String.self, forKey: .packaging)
|
|
||||||
packagingDebugTags = try container.decodeIfPresent([String].self, forKey: .packagingDebugTags)
|
|
||||||
packagingTags = try container.decodeIfPresent([String].self, forKey: .packagingTags)
|
|
||||||
photographersTags = try container.decodeIfPresent([String].self, forKey: .photographersTags)
|
|
||||||
pnnsGroups1 = try container.decodeIfPresent(String.self, forKey: .pnnsGroups1)
|
|
||||||
pnnsGroups2 = try container.decodeIfPresent(String.self, forKey: .pnnsGroups2)
|
|
||||||
pnnsGroups1Tags = try container.decodeIfPresent([String].self, forKey: .pnnsGroups1Tags)
|
|
||||||
pnnsGroups2Tags = try container.decodeIfPresent([String].self, forKey: .pnnsGroups2Tags)
|
|
||||||
popularityKey = try container.decodeIfPresent(Float.self, forKey: .popularityKey)
|
|
||||||
producerVersionId = try container.decodeIfPresent(String.self, forKey: .producerVersionId)
|
|
||||||
productName = try container.decodeIfPresent(String.self, forKey: .productName)
|
|
||||||
purchasePlaces = try container.decodeIfPresent(String.self, forKey: .purchasePlaces)
|
|
||||||
purchasePlacesDebugTags = try container.decodeIfPresent([String].self, forKey: .purchasePlacesDebugTags)
|
|
||||||
purchasePlacesTags = try container.decodeIfPresent([String].self, forKey: .purchasePlacesTags)
|
|
||||||
qualityTags = try container.decodeIfPresent([String].self, forKey: .qualityTags)
|
|
||||||
quantity = try container.decodeIfPresent(String.self, forKey: .quantity)
|
|
||||||
quantityDebugTags = try container.decodeIfPresent([String].self, forKey: .quantityDebugTags)
|
|
||||||
recyclingInstructionsToDiscard = try container.decodeIfPresent(String.self, forKey: .recyclingInstructionsToDiscard)
|
|
||||||
rev = try container.decodeIfPresent(Float.self, forKey: .rev)
|
|
||||||
if container.contains(.servingQuantity) {
|
|
||||||
if try container.decodeNil(forKey: .servingQuantity) {
|
|
||||||
servingQuantity = nil
|
|
||||||
} else {
|
|
||||||
if let floatValue = try? container.decode(Float.self, forKey: .servingQuantity) {
|
|
||||||
servingQuantity = "\(floatValue)"
|
|
||||||
} else if let stringValue = try? container.decode(String.self, forKey: .servingQuantity) {
|
|
||||||
servingQuantity = stringValue
|
|
||||||
}else {
|
|
||||||
// If decoding as both Float and String fails, handle the error accordingly
|
|
||||||
throw DecodingError.dataCorruptedError(
|
|
||||||
forKey: .servingQuantity,
|
|
||||||
in: container,
|
|
||||||
debugDescription: "Unable to decode servingQuantity"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
servingQuantity = nil
|
|
||||||
}
|
|
||||||
servingSize = try container.decodeIfPresent(String.self, forKey: .servingSize)
|
|
||||||
servingSizeDebugTags = try container.decodeIfPresent([String].self, forKey: .servingSizeDebugTags)
|
|
||||||
sortkey = try container.decodeIfPresent(Float.self, forKey: .sortkey)
|
|
||||||
states = try container.decodeIfPresent(String.self, forKey: .states)
|
|
||||||
statesHierarchy = try container.decodeIfPresent([String].self, forKey: .statesHierarchy)
|
|
||||||
statesTags = try container.decodeIfPresent([String].self, forKey: .statesTags)
|
|
||||||
stores = try container.decodeIfPresent(String.self, forKey: .stores)
|
|
||||||
storesDebugTags = try container.decodeIfPresent([String].self, forKey: .storesDebugTags)
|
|
||||||
storesTags = try container.decodeIfPresent([String].self, forKey: .storesTags)
|
|
||||||
traces = try container.decodeIfPresent(String.self, forKey: .traces)
|
|
||||||
tracesFromIngredients = try container.decodeIfPresent(String.self, forKey: .tracesFromIngredients)
|
|
||||||
tracesHierarchy = try container.decodeIfPresent([String].self, forKey: .tracesHierarchy)
|
|
||||||
tracesDebugTags = try container.decodeIfPresent([String].self, forKey: .tracesDebugTags)
|
|
||||||
tracesFromUser = try container.decodeIfPresent(String.self, forKey: .tracesFromUser)
|
|
||||||
tracesLc = try container.decodeIfPresent(String.self, forKey: .tracesLc)
|
|
||||||
tracesTags = try container.decodeIfPresent([String].self, forKey: .tracesTags)
|
|
||||||
if container.contains(.unknownIngredientsN) {
|
|
||||||
if try container.decodeNil(forKey: .unknownIngredientsN) {
|
|
||||||
unknownIngredientsN = nil
|
|
||||||
} else {
|
|
||||||
if let intValue = try? container.decode(Float.self, forKey: .unknownIngredientsN) {
|
|
||||||
unknownIngredientsN = intValue
|
|
||||||
} else if let stringValue = try? container.decode(String.self, forKey: .unknownIngredientsN) {
|
|
||||||
unknownIngredientsN = Float(stringValue)
|
|
||||||
}else {
|
|
||||||
// If decoding as both Float and String fails, handle the error accordingly
|
|
||||||
throw DecodingError.dataCorruptedError(
|
|
||||||
forKey: .unknownIngredientsN,
|
|
||||||
in: container,
|
|
||||||
debugDescription: "Unable to decode unknownIngredientsN"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unknownIngredientsN = nil
|
|
||||||
}
|
|
||||||
unknownNutrientsTags = try container.decodeIfPresent([String].self, forKey: .unknownNutrientsTags)
|
|
||||||
updateKey = try container.decodeIfPresent(String.self, forKey: .updateKey)
|
|
||||||
vitaminsPrevTags = try container.decodeIfPresent([String].self, forKey: .vitaminsPrevTags)
|
|
||||||
vitaminsTags = try container.decodeIfPresent([String].self, forKey: .vitaminsTags)
|
|
||||||
|
|
||||||
// Check for null value
|
|
||||||
if container.contains(.productQuantity) {
|
|
||||||
if try container.decodeNil(forKey: .productQuantity) {
|
|
||||||
productQuantity = nil
|
|
||||||
} else {
|
|
||||||
// Try to decode as Float
|
|
||||||
if let floatValue = try? container.decode(Float.self, forKey: .productQuantity) {
|
|
||||||
productQuantity = floatValue
|
|
||||||
} else if let stringValue = try? container.decode(String.self, forKey: .productQuantity) {
|
|
||||||
// If decoding as Float fails, try to decode as String
|
|
||||||
productQuantity = Float(stringValue)
|
|
||||||
} else {
|
|
||||||
// If decoding as both Float and String fails, handle the error accordingly
|
|
||||||
throw DecodingError.dataCorruptedError(
|
|
||||||
forKey: .productQuantity,
|
|
||||||
in: container,
|
|
||||||
debugDescription: "Unable to decode productQuantity"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
productQuantity = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... (initialize other properties)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
|
|
||||||
public struct ProductResponse: Codable, ObjectDebugger {
|
|
||||||
public var product: Product?
|
|
||||||
public var code: String?
|
|
||||||
public var status: Int? // or Bool, depending on your needs
|
|
||||||
public var statusVerbose: String?
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
|
||||||
case product
|
|
||||||
case code
|
|
||||||
case status
|
|
||||||
case statusVerbose = "status_verbose"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
public enum SearchNutriment: String, Codable {
|
|
||||||
case energy // Energy
|
|
||||||
case energyFromFat = "energy-from-fat" // Energy from fat
|
|
||||||
case fat // Fat
|
|
||||||
case saturatedFat = "saturated-fat" // Saturated fat
|
|
||||||
case butyricAcid = "butyric-acid" // Butyric acid (4:0)
|
|
||||||
case caproicAcid = "caproic-acid" // Caproic acid (6:0)
|
|
||||||
case caprylicAcid = "caprylic-acid" // Caprylic acid (8:0)
|
|
||||||
case capricAcid = "capric-acid" // Capric acid (10:0)
|
|
||||||
case lauricAcid = "lauric-acid" // Lauric acid (12:0)
|
|
||||||
case myristicAcid = "myristic-acid" // Myristic acid (14:0)
|
|
||||||
case palmiticAcid = "palmitic-acid" // Palmitic acid (16:0)
|
|
||||||
case stearicAcid = "stearic-acid" // Stearic acid (18:0)
|
|
||||||
case arachidicAcid = "arachidic-acid" // Arachidic acid (20:0)
|
|
||||||
case behenicAcid = "behenic-acid" // Behenic acid (22:0)
|
|
||||||
case lignocericAcid = "lignoceric-acid" // Lignoceric acid (24:0)
|
|
||||||
case ceroticAcid = "cerotic-acid" // Cerotic acid (26:0)
|
|
||||||
case montanicAcid = "montanic-acid" // Montanic acid (28:0)
|
|
||||||
case melissicAcid = "melissic-acid" // Melissic acid (30:0)
|
|
||||||
case monounsaturatedFat = "monounsaturated-fat" // Monounsaturated fat
|
|
||||||
case polyunsaturatedFat = "polyunsaturated-fat" // Polyunsaturated fat
|
|
||||||
case omega3Fat = "omega-3-fat" // Omega 3 fatty acids
|
|
||||||
case alphaLinolenicAcid = "alpha-linolenic-acid" // Alpha-linolenic acid / ALA (18:3 n-3)
|
|
||||||
case eicosapentaenoicAcid = "eicosapentaenoic-acid" // Eicosapentaenoic acid / EPA (20:5 n-3)
|
|
||||||
case docosahexaenoicAcid = "docosahexaenoic-acid" // Docosahexaenoic acid / DHA (22:6 n-3)
|
|
||||||
case omega6Fat = "omega-6-fat" // Omega 6 fatty acids
|
|
||||||
case linoleicAcid = "linoleic-acid" // Linoleic acid / LA (18:2 n-6)
|
|
||||||
case arachidonicAcid = "arachidonic-acid" // Arachidonic acid / AA / ARA (20:4 n-6)
|
|
||||||
case gammaLinolenicAcid = "gamma-linolenic-acid" // Gamma-linolenic acid / GLA (18:3 n-6)
|
|
||||||
case dihomoGammaLinolenicAcid = "dihomo-gamma-linolenic-acid" // Dihomo-gamma-linolenic acid / DGLA (20:3 n-6)
|
|
||||||
case omega9Fat = "omega-9-fat" // Omega 9 fatty acids
|
|
||||||
case oleicAcid = "oleic-acid" // Oleic acid (18:1 n-9)
|
|
||||||
case elaidicAcid = "elaidic-acid" // Elaidic acid (18:1 n-9)
|
|
||||||
case gondoicAcid = "gondoic-acid" // Gondoic acid (20:1 n-9)
|
|
||||||
case meadAcid = "mead-acid" // Mead acid (20:3 n-9)
|
|
||||||
case erucicAcid = "erucic-acid" // Erucic acid (22:1 n-9)
|
|
||||||
case nervonicAcid = "nervonic-acid" // Nervonic acid (24:1 n-9)
|
|
||||||
case transFat = "trans-fat" // Trans fat
|
|
||||||
case cholesterol // Cholesterol
|
|
||||||
case carbohydrates // Carbohydrate
|
|
||||||
case sugars // Sugars
|
|
||||||
case sucrose // Sucrose
|
|
||||||
case glucose // Glucose
|
|
||||||
case fructose // Fructose
|
|
||||||
case lactose // Lactose
|
|
||||||
case maltose // Maltose
|
|
||||||
case maltodextrins // Maltodextrins
|
|
||||||
case starch // Starch
|
|
||||||
case polyols // Sugar alcohols (Polyols)
|
|
||||||
case fiber // Dietary fiber
|
|
||||||
case proteins // Proteins
|
|
||||||
case casein // Casein
|
|
||||||
case serumProteins = "serum-proteins" // Serum proteins
|
|
||||||
case nucleotides // Nucleotides
|
|
||||||
case salt // Salt
|
|
||||||
case sodium // Sodium
|
|
||||||
case alcohol // Alcohol
|
|
||||||
case vitaminA = "vitamin-a" // Vitamin A
|
|
||||||
case betaCarotene = "beta-carotene" // Beta carotene
|
|
||||||
case vitaminD = "vitamin-d" // Vitamin D
|
|
||||||
case vitaminE = "vitamin-e" // Vitamin E
|
|
||||||
case vitaminK = "vitamin-k" // Vitamin K
|
|
||||||
case vitaminC = "vitamin-c" // Vitamin C (ascorbic acid)
|
|
||||||
case vitaminB1 = "vitamin-b1" // Vitamin B1 (Thiamin)
|
|
||||||
case vitaminB2 = "vitamin-b2" // Vitamin B2 (Riboflavin)
|
|
||||||
case vitaminPP = "vitamin-pp" // Vitamin B3 / Vitamin PP (Niacin)
|
|
||||||
case vitaminB6 = "vitamin-b6" // Vitamin B6 (Pyridoxin)
|
|
||||||
case vitaminB9 = "vitamin-b9" // Vitamin B9 (Folic acid / Folates)
|
|
||||||
case vitaminB12 = "vitamin-b12" // Vitamin B12 (Cobalamin)
|
|
||||||
case biotin // Biotin
|
|
||||||
case pantothenicAcid = "pantothenic-acid" // Pantothenic acid / Pantothenate (Vitamin B5)
|
|
||||||
case silica // Silica
|
|
||||||
case bicarbonate // Bicarbonate
|
|
||||||
case potassium // Potassium
|
|
||||||
case chloride // Chloride
|
|
||||||
case calcium // Calcium
|
|
||||||
case phosphorus // Phosphorus
|
|
||||||
case iron // Iron
|
|
||||||
case magnesium // Magnesium
|
|
||||||
case zinc // Zinc
|
|
||||||
case copper // Copper
|
|
||||||
case manganese // Manganese
|
|
||||||
case fluoride // Fluoride
|
|
||||||
case selenium // Selenium
|
|
||||||
case chromium // Chromium
|
|
||||||
case molybdenum // Molybdenum
|
|
||||||
case iodine // Iodine
|
|
||||||
case caffeine // Caffeine
|
|
||||||
case taurine // Taurine
|
|
||||||
case pH // pH
|
|
||||||
case fruitsVegetablesNuts = "fruits-vegetables-nuts" // Fruits, vegetables, and nuts (minimum)
|
|
||||||
case collagenMeatProteinRatio = "collagen-meat-protein-ratio" // Collagen/Meat protein ratio (maximum)
|
|
||||||
case cocoa // Cocoa (minimum)
|
|
||||||
case chlorophyll = "chlorophyll" // Chlorophyll
|
|
||||||
case carbonFootprint = "carbon-footprint" // Carbon footprint / CO2 emissions
|
|
||||||
case nutritionScoreFR = "nutrition-score-fr" // Experimental nutrition score
|
|
||||||
case nutritionScoreUK = "nutrition-score-uk" // Nutrition score - UK
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
public struct SearchResponse: Codable, ObjectDebugger {
|
|
||||||
public var count: Int
|
|
||||||
public var page: Int
|
|
||||||
public var pageCount: Int
|
|
||||||
public var pageSize: Int
|
|
||||||
public var products: [Product]?
|
|
||||||
public var skip: Int
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
|
||||||
case count, page, products, skip
|
|
||||||
case pageCount = "page_count"
|
|
||||||
case pageSize = "page_size"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
public enum SearchTag: String, Codable {
|
|
||||||
case brands // Brands
|
|
||||||
case categories // Categories
|
|
||||||
case packaging // Packaging
|
|
||||||
case labels // Labels
|
|
||||||
case origins // Origins of ingredients
|
|
||||||
case manufacturingPlaces = "manufacturing_places" // Manufacturing or processing places
|
|
||||||
case embCodes = "emb_codes" // Packager codes
|
|
||||||
case purchasePlaces = "purchase_places" // Purchase places
|
|
||||||
case stores // Stores
|
|
||||||
case countries // Countries
|
|
||||||
case additives // Additives
|
|
||||||
case allergens // Allergens
|
|
||||||
case traces // Traces
|
|
||||||
case nutritionGrades = "nutrition_grades" // Nutrition grades
|
|
||||||
case states // States
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
public class SelectedImage: Codable, ObjectDebugger {
|
|
||||||
public var display: SelectedImageItem?
|
|
||||||
public var small: SelectedImageItem?
|
|
||||||
public var thumb: SelectedImageItem?
|
|
||||||
|
|
||||||
public init(display: SelectedImageItem?, small: SelectedImageItem?, thumb: SelectedImageItem?) {
|
|
||||||
self.display = display
|
|
||||||
self.small = small
|
|
||||||
self.thumb = thumb
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
public struct SelectedImageItem: Codable, ObjectDebugger {
|
|
||||||
public var en: String?
|
|
||||||
public var fr: String?
|
|
||||||
public var pl: String?
|
|
||||||
|
|
||||||
public var url: String {
|
|
||||||
[en, fr, pl].compactMap { $0 }.first ?? ""
|
|
||||||
}
|
|
||||||
|
|
||||||
public init(en: String?, fr: String?, pl: String?) {
|
|
||||||
self.en = en
|
|
||||||
self.fr = fr
|
|
||||||
self.pl = pl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
public struct SelectedImages: Codable, ObjectDebugger {
|
|
||||||
public var front: SelectedImage?
|
|
||||||
public var ingredients: SelectedImage?
|
|
||||||
public var nutrition: SelectedImage?
|
|
||||||
|
|
||||||
public init(front: SelectedImage?, ingredients: SelectedImage?, nutrition: SelectedImage?) {
|
|
||||||
self.front = front
|
|
||||||
self.ingredients = ingredients
|
|
||||||
self.nutrition = nutrition
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
public struct Source: Codable, ObjectDebugger {
|
|
||||||
public let fields: [String] = []
|
|
||||||
public let id: String? = nil
|
|
||||||
public let images: [String] = []
|
|
||||||
public let importT: Int = 0
|
|
||||||
public let manufacturer: String? = nil
|
|
||||||
public let name: String? = nil
|
|
||||||
public let url: String? = nil
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
|
||||||
case fields
|
|
||||||
case id
|
|
||||||
case images
|
|
||||||
case importT = "import_t"
|
|
||||||
case manufacturer
|
|
||||||
case name
|
|
||||||
case url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user