MongoView/MongoView/Node.swift

211 lines
5.8 KiB
Swift

//
// 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)"
}
}
var typeString: String {
switch value {
case .double(_):
return "Double"
case .string(_):
return "String"
case .document(_):
return "Document"
case .array(_):
return "Array"
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 "UUID"
case .md5:
return "MD5 hash"
case .userDefined:
return "User defined binary data"
}
case .undefined:
return "Undefined"
case .objectId(_):
return "ObjectId"
case .bool(_):
return "Bool"
case .datetime(_):
return "DateTime"
case .null:
return "Null"
case .regex(_):
return "RegEx"
case .dbPointer(_):
return "DBRef"
case .symbol(_):
return "Symbol"
case .code(_):
return "Code"
case .codeWithScope(_):
return "Code with scope"
case .int32(_):
return "Int32"
case .timestamp(_):
return "Timestamp"
case .int64(_):
return "Int64"
case .decimal128(_):
return "Decimal128"
case .minKey:
return "MinKey"
case .maxKey:
return "MaxKey"
}
}
}