//////////////////////////////////////////////////////////////////////////// // // Copyright 2020 Realm Inc. // // Licensed 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 Realm /** :nodoc: **/ public extension ObjectiveCSupport { // FIXME: remove these and rename convertBson to convert on the next major // version bump static func convert(object: AnyBSON?) -> RLMBSON? { if let converted = object.map(self.convertBson), !(converted is NSNull) { return converted } return nil } static func convert(object: RLMBSON?) -> AnyBSON? { if let object = object { let converted = convertBson(object: object) if converted == .null { return nil } return converted } return nil } static func convert(_ object: Document) -> [String: RLMBSON] { object.reduce(into: Dictionary<String, RLMBSON>()) { (result: inout [String: RLMBSON], kvp) in result[kvp.key] = kvp.value.map(convertBson) ?? NSNull() } } /// Convert an `AnyBSON` to a `RLMBSON`. static func convertBson(object: AnyBSON) -> RLMBSON { switch object { case .int32(let val): return val as NSNumber case .int64(let val): return val as NSNumber case .double(let val): return val as NSNumber case .string(let val): return val as NSString case .binary(let val): return val as NSData case .datetime(let val): return val as NSDate case .timestamp(let val): return val as NSDate case .decimal128(let val): return val as RLMDecimal128 case .objectId(let val): return val as RLMObjectId case .document(let val): return convert(val) as NSDictionary case .array(let val): return val.map { $0.map(convertBson) } as NSArray case .maxKey: return MaxKey() case .minKey: return MinKey() case .regex(let val): return val case .bool(let val): return val as NSNumber case .uuid(let val): return val as NSUUID case .null: return NSNull() } } static func convert(_ object: [String: RLMBSON]) -> Document { object.mapValues { convert(object: $0) } } /// Convert a `RLMBSON` to an `AnyBSON`. static func convertBson(object bson: RLMBSON) -> AnyBSON? { switch bson.__bsonType { case .null: return .null case .int32: guard let val = bson as? NSNumber else { return nil } return .int32(Int32(val.intValue)) case .int64: guard let val = bson as? NSNumber else { return nil } return .int64(Int64(val.int64Value)) case .bool: guard let val = bson as? NSNumber else { return nil } return .bool(val.boolValue) case .double: guard let val = bson as? NSNumber else { return nil } return .double(val.doubleValue) case .string: guard let val = bson as? NSString else { return nil } return .string(val as String) case .binary: guard let val = bson as? NSData else { return nil } return .binary(val as Data) case .timestamp: guard let val = bson as? NSDate else { return nil } return .timestamp(val as Date) case .datetime: guard let val = bson as? NSDate else { return nil } return .datetime(val as Date) case .objectId: guard let val = bson as? RLMObjectId, let oid = try? ObjectId(string: val.stringValue) else { return nil } return .objectId(oid) case .decimal128: guard let val = bson as? RLMDecimal128 else { return nil } return .decimal128(Decimal128(stringLiteral: val.stringValue)) case .regularExpression: guard let val = bson as? NSRegularExpression else { return nil } return .regex(val) case .maxKey: return .maxKey case .minKey: return .minKey case .document: guard let val = bson as? Dictionary<String, RLMBSON> else { return nil } return .document(convert(val)) case .array: guard let val = bson as? Array<RLMBSON?> else { return nil } return .array(val.compactMap { if let value = $0 { return convertBson(object: value) } return .null }.map { (v: AnyBSON) -> AnyBSON? in v == .null ? nil : v }) case .UUID: guard let val = bson as? NSUUID else { return nil } return .uuid(val as UUID) default: return nil } } }