// // MongoEvaluator.swift // MongoView // // Created by Shadowfacts on 1/12/20. // Copyright © 2020 Shadowfacts. All rights reserved. // import Foundation import JavaScriptCore import MongoSwift struct MongoEvaluator { static let context: JSContext = { let context = JSContext()! let date: @convention(block) (JSValue) -> Dictionary = { (input) in ["$date": input] } let functions: [NSString: @convention(block) (JSValue) -> Dictionary] = [ "ObjectId": { (input) in ["$oid": input] }, "NumberLong": { (input) in ["$numberLong": input] }, "NumberInt": { (input) in ["$numberInt": input] }, "NumberDecimal": { (input) in ["$numberDecimal": input] }, "Date": date, "ISODate": date, ] functions.forEach { (key, value) in context.setObject(value, forKeyedSubscript: key) } let dbRef: @convention(block) (String, String) -> Dictionary = { (ref, id) in ["$ref": ref, "$id": ["$oid": id]] } context.setObject(dbRef, forKeyedSubscript: "DBRef" as NSString) return context }() static func parse(shellJSON: String) -> Document? { guard !shellJSON.isEmpty, let result = context.evaluateScript("JSON.stringify(\(shellJSON))") else { return nil } do { return try Document(fromJSON: result.toString()) } catch { print("Unable to parse Document: \(error)") return nil } } static func eval(command: String, connectingTo connStr: String) -> [Document] { print("Running command \"\(command)\" against \(connStr)") let mongoOutputPipe = Pipe() let mongoProcess = Process() mongoProcess.launchPath = "/usr/local/bin/mongo" mongoProcess.arguments = [connStr, "--quiet", "--norc", "--eval", command] mongoProcess.standardOutput = mongoOutputPipe mongoProcess.launch() let mongoOutputHandle = mongoOutputPipe.fileHandleForReading var strs = [String]() var data: Data! repeat { data = mongoOutputHandle.availableData strs.append(String(data: data, encoding: .utf8)!) } while (data.count > 0) mongoOutputHandle.closeFile() let lines = strs.joined(separator: "").components(separatedBy: "\n") return lines.compactMap(parse(shellJSON:)) } }