// // Node.swift // MongoView // // Created by Shadowfacts on 1/9/20. // Copyright © 2020 Shadowfacts. All rights reserved. // import Foundation import MongoSwift class Node { let key: Key? let value: BSON lazy private(set) var children: [Node] = { switch value { case let .array(array): return array.enumerated().map { (index, val) in Node(key: .index(index), value: val) } case let .document(doc): return doc.map { (key, val) in Node(key: .name(key), value: val) } default: return [] } }() var numberOfChildren: Int { children.count } var hasChildren: Bool { numberOfChildren > 0 } init(key: Key? = nil, value: BSON) { self.key = key self.value = value } convenience init(document: Document) { if case let .objectId(id) = document["_id"] { self.init(key: .objectId(id), value: .document(document)) } else { self.init(key: nil, value: .document(document)) } } } extension Node { enum Key { case index(Int) case name(String) case objectId(ObjectId) } } extension Node { static let dateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.locale = .current formatter.setLocalizedDateFormatFromTemplate("yyyy-MM-dd HH:mm:ss ZZ") return formatter }() var keyString: String { switch key { case nil: return "" case let .index(index): return index.description case let .name(name): return name case let .objectId(id): return id.description } } var valueString: String { switch value { case let .double(value): return value.description case let .string(value): return value case let .document(doc): return "(\(doc.count) field\(doc.count == 1 ? "" : "s"))" case let .array(array): return "(\(array.count) element\(array.count == 1 ? "" : "s"))" case let .binary(value): switch Binary.Subtype(rawValue: value.subtype) { case nil: return "(unknown binary data)" case .generic: return "(generic binary data)" case .function: return "(function binary data)" case .binaryDeprecated: return "(binary data)" case .uuidDeprecated: fallthrough case .uuid: return try! UUID(from: value).description case .md5: return "(MD5 binary data)" case .userDefined: return "(user defined binary data)" } case .undefined: return "undefined" case let .objectId(value): return value.description case let .bool(value): return value.description case let .datetime(value): return value.description case .null: return "null" case let .regex(value): return try! NSRegularExpression(from: value).description case let .dbPointer(value): return "\(value.ref)(\(value.id))" case let .symbol(value): return value.description case let .code(value): return value.code case let .codeWithScope(value): return value.code case let .int32(value): return value.description case let .timestamp(value): let date = Date(timeIntervalSince1970: TimeInterval(value.timestamp)) return Node.dateFormatter.string(from: date) case let .int64(value): return value.description case let .decimal128(value): return value.description case .minKey: return "(min key)" case .maxKey: return "(max key)" } } }