diff --git a/CHANGELOG.md b/CHANGELOG.md index 87e36fe..dfa9770 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.4.3] - 2024-11-12 +## [0.4.4] - 2024-12-05 +- Changed: Differentiate cache also by data provided (e.g. domain filter for states) + +## [0.4.3] - 2024-12-03 - Changed: Allow passing data to entities state subcription, so you can filter what you want to receive ## [0.4.2] - 2024-04-22 diff --git a/HAKit.podspec b/HAKit.podspec index abae865..e923bc1 100644 --- a/HAKit.podspec +++ b/HAKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'HAKit' - s.version = '0.4.3' + s.version = '0.4.4' s.summary = 'Communicate with a Home Assistant instance.' s.author = 'Home Assistant' diff --git a/README.md b/README.md index 7d6b493..76b7e9f 100644 --- a/README.md +++ b/README.md @@ -220,7 +220,7 @@ To add it to an Xcode project, you can do this by adding the URL to File > Swift Add the following line to your Podfile: ```ruby -pod "HAKit", "~> 0.4.3" +pod "HAKit", "~> 0.4.4" # We are working from a fork of Starscream due to a necessary fix, please specify in your podfile pod 'Starscream', git: 'https://github.com/bgoncal/starscream', branch: 'ha-URLSession-fix' # pod "HAKit/PromiseKit" # optional, for PromiseKit support diff --git a/Source/Caches/HACachesContainer.swift b/Source/Caches/HACachesContainer.swift index 19aff69..cc63ef7 100644 --- a/Source/Caches/HACachesContainer.swift +++ b/Source/Caches/HACachesContainer.swift @@ -1,3 +1,5 @@ +import Foundation + /// A cache key for `HACachesContainer` public protocol HACacheKey { /// The value type in the cache, e.g. `T` in `HACache` @@ -40,9 +42,14 @@ public protocol HACacheKey { /// /// Then, access it from a connection like `connection.caches.yourValueType`. public class HACachesContainer { + struct CacheEntry { + let data: [String: Any] + let cache: Any + } + /// Our current initialized caches. We key by the ObjectIdentifier of the meta type, which guarantees a unique /// cache entry per key since the identifier is globally unique per type. - private var values: [ObjectIdentifier: Any] = [:] + private(set) var values: [ObjectIdentifier: [CacheEntry]] = [:] /// The connection we're chained off. This is unowned to avoid a cyclic reference. We expect to crash in this case. internal unowned let connection: HAConnection @@ -65,12 +72,26 @@ public class HACachesContainer { // ObjectIdentifier is globally unique per class _or_ meta type, and we're using meta type here let key = ObjectIdentifier(KeyType.self) - if let value = values[key] as? HACache { - return value + if let cacheEntries = values[key], let cacheEntry = cacheEntries.first(where: { entry in + // Avoid unecessary json serialization to compare dictionaries + if entry.data.isEmpty, data.isEmpty { + return true + } + + let currentData = try? JSONSerialization.data(withJSONObject: entry.data, options: .prettyPrinted) + let requestedData = try? JSONSerialization.data(withJSONObject: data, options: .prettyPrinted) + + return currentData == requestedData + }), let cache = cacheEntry.cache as? HACache { + return cache } - let value = KeyType.create(connection: connection, data: data) - values[key] = value - return value + let cache = KeyType.create(connection: connection, data: data) + if values[key] == nil { + values[key] = [.init(data: data, cache: cache)] + } else { + values[key]?.append(CacheEntry(data: data, cache: cache)) + } + return cache } } diff --git a/Tests/HACachesContainer.test.swift b/Tests/HACachesContainer.test.swift index bb4a192..0706c60 100644 --- a/Tests/HACachesContainer.test.swift +++ b/Tests/HACachesContainer.test.swift @@ -38,6 +38,20 @@ internal class HACachesContainerTests: XCTestCase { let cache2 = container[Key2.self] XCTAssertNotEqual(ObjectIdentifier(cache1), ObjectIdentifier(cache2)) } + + func testSameKeyWithDifferentDataReturnsDifferentCache() { + _ = container.states(["abc": "def"]) + _ = container.states(["123": "456"]) + + XCTAssertEqual(container.values.first?.value.count, 2) + } + + func testSameKeyWithSameDataReturnsSameCache() { + _ = container.states(["abc": "def"]) + _ = container.states(["abc": "def"]) + + XCTAssertEqual(container.values.first?.value.count, 1) + } } private struct Key1: HACacheKey {