Skip to content

Commit

Permalink
Differentiate caches also by data provided (e.g. domain filter for en…
Browse files Browse the repository at this point in the history
…titity states) (#70)

* Differentiate caches also by data param provided

* Bump version

* Update implementation

* Lint
  • Loading branch information
bgoncal authored Dec 5, 2024
1 parent ea810be commit 13d7712
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 9 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion HAKit.podspec
Original file line number Diff line number Diff line change
@@ -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'

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
33 changes: 27 additions & 6 deletions Source/Caches/HACachesContainer.swift
Original file line number Diff line number Diff line change
@@ -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<T>`
Expand Down Expand Up @@ -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

Expand All @@ -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<KeyType.Value> {
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<KeyType.Value> {
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
}
}
14 changes: 14 additions & 0 deletions Tests/HACachesContainer.test.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 13d7712

Please sign in to comment.