From 94f5befff6d45f1dc5579fd1b842ec0a2addc229 Mon Sep 17 00:00:00 2001 From: Andi Date: Mon, 7 Feb 2022 00:23:09 +0100 Subject: [PATCH] Add option to allow ContextKey overwrite on `unsafeAdd` (#5) * Add option to allow ContextKey overwrite on `unsafeAdd` * Swiftlint --- Sources/ApodiniContext/CodableContextKey.swift | 3 +++ Sources/ApodiniContext/Context.swift | 6 ++++-- .../ApodiniContextTests/ContextKeyTests.swift | 18 +++++++++++++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Sources/ApodiniContext/CodableContextKey.swift b/Sources/ApodiniContext/CodableContextKey.swift index d8b0883..68b1556 100644 --- a/Sources/ApodiniContext/CodableContextKey.swift +++ b/Sources/ApodiniContext/CodableContextKey.swift @@ -24,10 +24,12 @@ private let encoder = JSONEncoder() private let decoder = JSONDecoder() extension CodableContextKey { + /// Default identifier is derived from the swift type name public static var identifier: String { "\(Self.self)" } + /// Default implementation for anyEncode to base64 string. public static func anyEncode(value: Any) throws -> String { guard let value = value as? Self.Value else { fatalError("CodableContextKey.anyEncode(value:) received illegal value type \(type(of: value)) instead of \(Value.self)") @@ -38,6 +40,7 @@ extension CodableContextKey { .base64EncodedString() } + /// Default implementation for decode from base64 string. public static func decode(from base64String: String) throws -> Value { guard let data = Data(base64Encoded: base64String) else { fatalError("Failed to unwrap bas64 encoded data string: \(base64String)") diff --git a/Sources/ApodiniContext/Context.swift b/Sources/ApodiniContext/Context.swift index 3507e66..5871275 100644 --- a/Sources/ApodiniContext/Context.swift +++ b/Sources/ApodiniContext/Context.swift @@ -89,10 +89,12 @@ public struct Context: ContextKeyRetrievable { /// - Parameters: /// - contextKey: The context to add value for. /// - value: The value to add. - public func unsafeAdd(_ contextKey: C.Type = C.self, value: C.Value) { + /// - allowOverwrite: This Bool controls if the unsafe addition should allow overwriting an existing entry. + /// Use this option with caution! This method does NOT reduce multiple values for the same key. It OVERWRITES! + public func unsafeAdd(_ contextKey: C.Type = C.self, value: C.Value, allowOverwrite: Bool = false) { let key = ObjectIdentifier(contextKey) - precondition(entries[key] == nil, "Cannot overwrite existing ContextKey entry with `unsafeAdd`: \(C.self): \(value)") + precondition(entries[key] == nil || allowOverwrite, "Cannot overwrite existing ContextKey entry with `unsafeAdd`: \(C.self): \(value)") if let codableContextKey = contextKey as? AnyCodableContextKey.Type { // we need to prevent this. as Otherwise we would need to handle merging this stuff which get really complex precondition(decodedEntries[codableContextKey.identifier] == nil, "Cannot overwrite existing CodableContextKey entry with `unsafeAdd`: \(C.self): \(value)") diff --git a/Tests/ApodiniContextTests/ContextKeyTests.swift b/Tests/ApodiniContextTests/ContextKeyTests.swift index 24e9a3c..1e16a20 100644 --- a/Tests/ApodiniContextTests/ContextKeyTests.swift +++ b/Tests/ApodiniContextTests/ContextKeyTests.swift @@ -107,11 +107,27 @@ class ContextKeyTests: XCTestCase { let decoder = FineJSONDecoder() let encodedContext = try encoder.encode(context) - XCTAssertEqual(String(data: encodedContext, encoding: .utf8), "{\"CodableArrayStringContextKey\":\"WyJIZWxsbyBTdW4iXQ==\",\"CodableStringContextKey\":\"IkhlbGxvIFdvcmxkIg==\"}") + XCTAssertEqual( + String(data: encodedContext, encoding: .utf8), + "{\"CodableArrayStringContextKey\":\"WyJIZWxsbyBTdW4iXQ==\",\"CodableStringContextKey\":\"IkhlbGxvIFdvcmxkIg==\"}" + ) let decodedContext = try decoder.decode(Context.self, from: encodedContext) XCTAssertEqual(decodedContext.get(valueFor: CodableStringContextKey.self), "Hello World") XCTAssertEqual(decodedContext.get(valueFor: RequiredCodableStringContextKey.self), "Default Value!") XCTAssertEqual(decodedContext.get(valueFor: CodableArrayStringContextKey.self), ["Hello Sun"]) } + + func testUnsafeAddAllowingOverwrite() { + struct CodableStringContextKey: CodableContextKey { + typealias Value = String + } + + let context = Context() + + context.unsafeAdd(CodableStringContextKey.self, value: "Hello World") + XCTAssertEqual(context.get(valueFor: CodableStringContextKey.self), "Hello World") + context.unsafeAdd(CodableStringContextKey.self, value: "Hello Mars", allowOverwrite: true) + XCTAssertEqual(context.get(valueFor: CodableStringContextKey.self), "Hello Mars") + } }