2020-01-11 19:42:28 +00:00
|
|
|
//
|
|
|
|
// 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.value = value
|
2020-01-28 03:20:02 +00:00
|
|
|
|
|
|
|
if key == nil,
|
|
|
|
case let .document(doc) = value,
|
|
|
|
case let .objectId(id) = doc["_id"] {
|
|
|
|
self.key = .objectId(id)
|
|
|
|
} else {
|
|
|
|
self.key = key
|
|
|
|
}
|
2020-01-11 19:42:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)"
|
|
|
|
}
|
|
|
|
}
|
2020-01-12 16:05:01 +00:00
|
|
|
|
|
|
|
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"
|
|
|
|
}
|
|
|
|
}
|
2020-01-11 19:42:28 +00:00
|
|
|
}
|