Sources/XCMetricsBackendLib/Common/Models/JSONValue.swift (67 lines of code) (raw):

// Copyright (c) 2020 Spotify AB. // // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. import Foundation /// Used to have a valid Fluent type that can be stored in a `JSON` column and conforms to `Codable` enum JSONValue: Equatable { case string(String) case number(Double) case object([String:JSONValue]) case array([JSONValue]) case bool(Bool) case null } extension JSONValue: Codable { func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { case let .array(array): try container.encode(array) case let .object(object): try container.encode(object) case let .string(string): try container.encode(string) case let .number(number): try container.encode(number) case let .bool(bool): try container.encode(bool) case .null: try container.encodeNil() } } init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() if let object = try? container.decode([String: JSONValue].self) { self = .object(object) } else if let array = try? container.decode([JSONValue].self) { self = .array(array) } else if let string = try? container.decode(String.self) { self = .string(string) } else if let bool = try? container.decode(Bool.self) { self = .bool(bool) } else if let number = try? container.decode(Double.self) { self = .number(number) } else if container.decodeNil() { self = .null } else { throw DecodingError.dataCorrupted( .init(codingPath: decoder.codingPath, debugDescription: "Invalid JSON value.") ) } } } extension JSONValue: CustomDebugStringConvertible { var debugDescription: String { switch self { case .string(let str): return str.debugDescription case .number(let num): return num.debugDescription case .bool(let bool): return bool.description case .null: return "null" default: let encoder = JSONEncoder() encoder.outputFormatting = [.prettyPrinted] return try! String(data: encoder.encode(self), encoding: .utf8)! } } } extension JSONValue: Hashable {}