Skip to content

Commit

Permalink
[WIP] Created PostedTransactionCache
Browse files Browse the repository at this point in the history
  • Loading branch information
NachoSoto committed Jul 27, 2023
1 parent 1de817f commit d3cd8ed
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 10 deletions.
4 changes: 4 additions & 0 deletions RevenueCat.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@
4F5C05BF2A43A2C500651C7D /* LocaleExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F5C05BE2A43A2C500651C7D /* LocaleExtensionsTests.swift */; };
4F5D52D92A5713A800E1C758 /* DebugViewSwiftUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FCEEA602A379CF9002C2112 /* DebugViewSwiftUITests.swift */; };
4F5D52EC2A57152B00E1C758 /* ImageSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FCEEA622A37A2E9002C2112 /* ImageSnapshot.swift */; };
4F6423F62A72C20F0071BFD1 /* PostedTransactionCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6423F52A72C20F0071BFD1 /* PostedTransactionCache.swift */; };
4F69EB092A14406E00ED6D4B /* Matchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F69EB082A14406E00ED6D4B /* Matchers.swift */; };
4F69EB0A2A14406E00ED6D4B /* Matchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F69EB082A14406E00ED6D4B /* Matchers.swift */; };
4F6BED592A26A14400CD9322 /* DebugView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6BED582A26A14400CD9322 /* DebugView.swift */; };
Expand Down Expand Up @@ -955,6 +956,7 @@
4F54DF412A1D8D0700FD72BF /* MockTransactionPoster.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTransactionPoster.swift; sourceTree = "<group>"; };
4F5C05BC2A43A21A00651C7D /* Locale+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Locale+Extensions.swift"; sourceTree = "<group>"; };
4F5C05BE2A43A2C500651C7D /* LocaleExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocaleExtensionsTests.swift; sourceTree = "<group>"; };
4F6423F52A72C20F0071BFD1 /* PostedTransactionCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostedTransactionCache.swift; sourceTree = "<group>"; };
4F69EB082A14406E00ED6D4B /* Matchers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Matchers.swift; sourceTree = "<group>"; };
4F6BED582A26A14400CD9322 /* DebugView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugView.swift; sourceTree = "<group>"; };
4F6BEDD82A26B55C00CD9322 /* DebugViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2601,6 +2603,7 @@
children = (
B3B5FBC0269E17CE00104A0C /* DeviceCache.swift */,
B3B5FBBE269E081E00104A0C /* InMemoryCachedObject.swift */,
4F6423F52A72C20F0071BFD1 /* PostedTransactionCache.swift */,
);
path = Caching;
sourceTree = "<group>";
Expand Down Expand Up @@ -3232,6 +3235,7 @@
57E6C27C29723A94001AFE98 /* Signing.swift in Sources */,
57CB2AD429CCF21A00C91439 /* RedirectLoggerTaskDelegate.swift in Sources */,
57C381DC27961547009E3940 /* SK2StoreProductDiscount.swift in Sources */,
4F6423F62A72C20F0071BFD1 /* PostedTransactionCache.swift in Sources */,
B34605CA279A6E380031CA74 /* GetCustomerInfoOperation.swift in Sources */,
5751379527F4C4D80064AB2C /* Optional+Extensions.swift in Sources */,
B3852FA026C1ED1F005384F8 /* IdentityManager.swift in Sources */,
Expand Down
40 changes: 30 additions & 10 deletions Sources/Caching/DeviceCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,26 @@ class DeviceCache {
Logger.verbose(Strings.purchase.device_cache_deinit(self))
}

// MARK: - generic methods

func update<Key: DeviceCacheKeyType, Value: Codable>(
key: Key,
default defaultValue: Value,
updater: @Sendable (inout Value) -> Void
) {
self.userDefaults.write {
var value: Value = $0.value(forKey: key) ?? defaultValue
updater(&value)
$0.set(value, forKey: key)
}
}

func value<Key: DeviceCacheKeyType, Value: Codable>(for key: Key) -> Value? {
self.userDefaults.read {
$0.value(forKey: key)
}
}

// MARK: - appUserID

func cache(appUserID: String) {
Expand Down Expand Up @@ -323,7 +343,7 @@ class DeviceCache {

// MARK: - Helper functions

internal enum CacheKeys: String, CacheKeyType {
internal enum CacheKeys: String, DeviceCacheKeyType {

case legacyGeneratedAppUserDefaults = "com.revenuecat.userdefaults.appUserID"
case appUserDefaults = "com.revenuecat.userdefaults.appUserID.new"
Expand All @@ -333,7 +353,7 @@ class DeviceCache {

}

fileprivate enum CacheKey: CacheKeyType {
fileprivate enum CacheKey: DeviceCacheKeyType {

static let base = "com.revenuecat.userdefaults."
static let legacySubscriberAttributesBase = "\(Self.base)subscriberAttributes."
Expand Down Expand Up @@ -564,35 +584,35 @@ private extension DeviceCache {

fileprivate extension UserDefaults {

func value<T: Decodable>(forKey key: CacheKeyType) -> T? {
func value<T: Decodable>(forKey key: DeviceCacheKeyType) -> T? {
guard let data = self.data(forKey: key) else {
return nil
}

return try? JSONDecoder.default.decode(jsonData: data, logErrors: true)
}

func set(_ value: Any?, forKey key: CacheKeyType) {
func set(_ value: Any?, forKey key: DeviceCacheKeyType) {
self.set(value, forKey: key.rawValue)
}

func string(forKey defaultName: CacheKeyType) -> String? {
func string(forKey defaultName: DeviceCacheKeyType) -> String? {
return self.string(forKey: defaultName.rawValue)
}

func removeObject(forKey defaultName: CacheKeyType) {
func removeObject(forKey defaultName: DeviceCacheKeyType) {
self.removeObject(forKey: defaultName.rawValue)
}

func dictionary(forKey defaultName: CacheKeyType) -> [String: Any]? {
func dictionary(forKey defaultName: DeviceCacheKeyType) -> [String: Any]? {
return self.dictionary(forKey: defaultName.rawValue)
}

func date(forKey defaultName: CacheKeyType) -> Date? {
func date(forKey defaultName: DeviceCacheKeyType) -> Date? {
return self.object(forKey: defaultName.rawValue) as? Date
}

func data(forKey key: CacheKeyType) -> Data? {
func data(forKey key: DeviceCacheKeyType) -> Data? {
return self.data(forKey: key.rawValue)
}

Expand Down Expand Up @@ -642,7 +662,7 @@ private extension DeviceCache {

}

private protocol CacheKeyType {
protocol DeviceCacheKeyType {

var rawValue: String { get }

Expand Down
58 changes: 58 additions & 0 deletions Sources/Caching/PostedTransactionCache.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// Copyright RevenueCat Inc. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// PostedTransactionCache.swift
//
// Created by Nacho Soto on 7/27/23.

import Foundation

protocol PostedTransactionCacheType {

func savePostedTransaction(_ transaction: StoreTransactionType)
func hasPostedTransaction(_ transaction: StoreTransactionType) -> Bool

}

// TODO: tests
// TODO: integrate

final class PostedTransactionCache: PostedTransactionCacheType {

private typealias StoredTransactions = Set<String>

private let deviceCache: DeviceCache

init(deviceCache: DeviceCache) {
self.deviceCache = deviceCache
}

func savePostedTransaction(_ transaction: StoreTransactionType) {
self.deviceCache.update(key: CacheKey.transactions,
default: Set<String>()) { transactions in
transactions.insert(transaction.transactionIdentifier)
}
}

func hasPostedTransaction(_ transaction: StoreTransactionType) -> Bool {
let transactions: StoredTransactions = self.deviceCache.value(for: CacheKey.transactions) ?? []
return transactions.contains(transaction.transactionIdentifier)
}

}

private extension PostedTransactionCache {

enum CacheKey: String, DeviceCacheKeyType {

case transactions = "com.revenuecat.cached_transaction_identifier"

}

}

0 comments on commit d3cd8ed

Please sign in to comment.