diff --git a/Gem/App.swift b/Gem/App.swift index d4bfd7eb..54feb776 100644 --- a/Gem/App.swift +++ b/Gem/App.swift @@ -20,6 +20,7 @@ struct GemApp: App { WalletCoordinator( db: db ) + .databaseContext(.readWrite { db.dbQueue }) .navigationBarTitleDisplayMode(.inline) .tint(Colors.black) } diff --git a/Gem/Asset/AssetScene.swift b/Gem/Asset/AssetScene.swift index c8490c0f..00ec7acb 100644 --- a/Gem/Asset/AssetScene.swift +++ b/Gem/Asset/AssetScene.swift @@ -51,9 +51,9 @@ struct AssetScene: View { self.wallet = wallet self.input = input _isPresentingAssetSelectType = isPresentingAssetSelectType - _assetData = Query(constant: input.assetRequest, in: \.db.dbQueue) - _transactions = Query(constant: input.transactionsRequest, in: \.db.dbQueue) - _banners = Query(constant: input.bannersRequest, in: \.db.dbQueue) + _assetData = Query(constant: input.assetRequest) + _transactions = Query(constant: input.transactionsRequest) + _banners = Query(constant: input.bannersRequest) } var body: some View { diff --git a/Gem/Assets/Scenes/SelectAssetScene.swift b/Gem/Assets/Scenes/SelectAssetScene.swift index a55c4c74..75d15227 100644 --- a/Gem/Assets/Scenes/SelectAssetScene.swift +++ b/Gem/Assets/Scenes/SelectAssetScene.swift @@ -8,7 +8,6 @@ import Style import Keystore struct SelectAssetScene: View { - @Environment(\.db) private var DB @Environment(\.keystore) private var keystore @Environment(\.walletsService) private var walletsService @Environment(\.nodeService) private var nodeService @@ -41,8 +40,8 @@ struct SelectAssetScene: View { } set: { new in model.filterModel.assetsRequest = new } - _assets = Query(request, in: \.db.dbQueue) - _assetInfo = Query(model.assetsInfoRequest, in: \.db.dbQueue) + _assets = Query(request) + _assetInfo = Query(model.assetsInfoRequest) } var body: some View { diff --git a/Gem/Charts/Scenes/ChartScene.swift b/Gem/Charts/Scenes/ChartScene.swift index e11213aa..6f135b8a 100644 --- a/Gem/Charts/Scenes/ChartScene.swift +++ b/Gem/Charts/Scenes/ChartScene.swift @@ -20,7 +20,7 @@ struct ChartScene: View { model: ChartsViewModel ) { _model = StateObject(wrappedValue: model) - _assetData = Query(constant: model.assetRequest, in: \.db.dbQueue) + _assetData = Query(constant: model.assetRequest) } var body: some View { diff --git a/Gem/Connections/Scenes/ConnectionsScene.swift b/Gem/Connections/Scenes/ConnectionsScene.swift index 1b72e587..59c9268e 100644 --- a/Gem/Connections/Scenes/ConnectionsScene.swift +++ b/Gem/Connections/Scenes/ConnectionsScene.swift @@ -9,8 +9,6 @@ import QRScanner import Style struct ConnectionsScene: View { - - @Environment(\.db) private var DB @Environment(\.keystore) private var keystore @State private var isPresentingScanner: Bool = false @State private var isPresentingErrorMessage: String? @@ -28,11 +26,9 @@ struct ConnectionsScene: View { let model: ConnectionsViewModel - init( - model: ConnectionsViewModel - ) { + init(model: ConnectionsViewModel) { self.model = model - _connections = Query(ConnectionsRequest(), in: \.db.dbQueue) + _connections = Query(constant: model.request) } var body: some View { diff --git a/Gem/Connections/ViewModels/ConnectionsViewModel.swift b/Gem/Connections/ViewModels/ConnectionsViewModel.swift index 165f35f5..fba0e076 100644 --- a/Gem/Connections/ViewModels/ConnectionsViewModel.swift +++ b/Gem/Connections/ViewModels/ConnectionsViewModel.swift @@ -2,10 +2,15 @@ import Foundation import Primitives +import Store struct ConnectionsViewModel { let service: ConnectionsService - + + var request: ConnectionsRequest { + ConnectionsRequest() + } + func addConnectionURI(uri: String, wallet: Wallet) async throws { try await service.addConnectionURI(uri: uri, wallet: wallet) } diff --git a/Gem/Core/Coordinator/WalletCoordinator.swift b/Gem/Core/Coordinator/WalletCoordinator.swift index 79d033d2..63bc1923 100644 --- a/Gem/Core/Coordinator/WalletCoordinator.swift +++ b/Gem/Core/Coordinator/WalletCoordinator.swift @@ -161,7 +161,6 @@ struct WalletCoordinator: View { } message: { Text(Localized.UpdateApp.description(updateAvailableAlertSheetMessage ?? "")) } - .environment(\.db, db) .environment(\.nodeService, nodeService) .environment(\.keystore, keystore) .environment(\.walletService, walletService) diff --git a/Gem/Core/Views/MainTabView.swift b/Gem/Core/Views/MainTabView.swift index 4e889d80..6cbc5f25 100644 --- a/Gem/Core/Views/MainTabView.swift +++ b/Gem/Core/Views/MainTabView.swift @@ -40,7 +40,7 @@ struct MainTabView: View { navigationStateManager: Binding ) { self.model = model - _transactions = Query(constant: model.transactionsCountRequest, in: \.db.dbQueue) + _transactions = Query(constant: model.transactionsCountRequest) _navigationStateManager = navigationStateManager } diff --git a/Gem/Stake/Scenes/StakeScene.swift b/Gem/Stake/Scenes/StakeScene.swift index f86cd89e..a9a55369 100644 --- a/Gem/Stake/Scenes/StakeScene.swift +++ b/Gem/Stake/Scenes/StakeScene.swift @@ -9,7 +9,6 @@ import Components import Style struct StakeScene: View { - @Environment(\.db) private var DB @Environment(\.keystore) private var keystore @Environment(\.nodeService) private var nodeService @Environment(\.walletsService) private var walletsService @@ -27,7 +26,7 @@ struct StakeScene: View { model: StakeViewModel ) { _model = State(initialValue: model) - _delegations = Query(model.request, in: \.db.dbQueue) + _delegations = Query(model.request) } var body: some View { diff --git a/Gem/Swap/Scenes/SwapScene.swift b/Gem/Swap/Scenes/SwapScene.swift index 2052cbf8..ced70e98 100644 --- a/Gem/Swap/Scenes/SwapScene.swift +++ b/Gem/Swap/Scenes/SwapScene.swift @@ -12,9 +12,14 @@ import Keystore struct SwapScene: View { @Environment(\.nodeService) private var nodeService - @Query var fromAsset: AssetData - @Query var toAsset: AssetData - @Query var tokenApprovals: [TransactionExtended] + @Query + var fromAsset: AssetData + + @Query + var toAsset: AssetData + + @Query + var tokenApprovals: [TransactionExtended] @State var model: SwapViewModel @@ -25,9 +30,9 @@ struct SwapScene: View { init(model: SwapViewModel) { _model = State(initialValue: model) - _fromAsset = Query(model.fromAssetRequest, in: \.db.dbQueue) - _toAsset = Query(model.toAssetRequest, in: \.db.dbQueue) - _tokenApprovals = Query(model.tokenApprovalsRequest, in: \.db.dbQueue) + _fromAsset = Query(model.fromAssetRequest) + _toAsset = Query(model.toAssetRequest) + _tokenApprovals = Query(model.tokenApprovalsRequest) } var body: some View { diff --git a/Gem/Transactions/Scenes/TransactionScene.swift b/Gem/Transactions/Scenes/TransactionScene.swift index 3d694a01..0bcc52e1 100644 --- a/Gem/Transactions/Scenes/TransactionScene.swift +++ b/Gem/Transactions/Scenes/TransactionScene.swift @@ -29,7 +29,7 @@ struct TransactionScene: View { input: TransactionSceneInput ) { self.input = input - _transactions = Query(input.transactionRequest, in: \.db.dbQueue) + _transactions = Query(input.transactionRequest) } @State private var showShareSheet = false diff --git a/Gem/Transactions/Scenes/TransactionsScene.swift b/Gem/Transactions/Scenes/TransactionsScene.swift index 7039c260..2c1be035 100644 --- a/Gem/Transactions/Scenes/TransactionsScene.swift +++ b/Gem/Transactions/Scenes/TransactionsScene.swift @@ -8,8 +8,6 @@ import Store import Style struct TransactionsScene: View { - @Environment(\.db) private var DB - @Query private var transactions: [TransactionExtended] @@ -19,7 +17,7 @@ struct TransactionsScene: View { model: TransactionsViewModel ) { self.model = model - _transactions = Query(constant: model.request, in: \.db.dbQueue) + _transactions = Query(constant: model.request) } var body: some View { diff --git a/Gem/Wallet/Scenes/WalletScene.swift b/Gem/Wallet/Scenes/WalletScene.swift index 85b16562..09bb0ca5 100644 --- a/Gem/Wallet/Scenes/WalletScene.swift +++ b/Gem/Wallet/Scenes/WalletScene.swift @@ -10,8 +10,6 @@ import GRDBQuery import Style struct WalletScene: View { - - @Environment(\.db) private var DB @Environment(\.keystore) private var keystore @Environment(\.assetsService) private var assetsService @Environment(\.transactionsService) private var transactionsService @@ -48,11 +46,11 @@ struct WalletScene: View { try? model.setupWallet() - _assets = Query(constant: model.assetsRequest, in: \.db.dbQueue) - _assetsPinned = Query(constant: model.assetsPinnedRequest, in: \.db.dbQueue) - _fiatValue = Query(constant: model.fiatValueRequest, in: \.db.dbQueue) - _dbWallet = Query(constant: model.walletRequest, in: \.db.dbQueue) - _banners = Query(constant: model.bannersRequest, in: \.db.dbQueue) + _assets = Query(constant: model.assetsRequest) + _assetsPinned = Query(constant: model.assetsPinnedRequest) + _fiatValue = Query(constant: model.fiatValueRequest) + _dbWallet = Query(constant: model.walletRequest) + _banners = Query(constant: model.bannersRequest) } var body: some View { diff --git a/Gem/Wallet/Types/Environment.swift b/Gem/Wallet/Types/Environment.swift index 772847ea..2312d2d6 100644 --- a/Gem/Wallet/Types/Environment.swift +++ b/Gem/Wallet/Types/Environment.swift @@ -7,10 +7,6 @@ import Store import Keystore import GemstonePrimitives -struct DatabaseQueueKey: EnvironmentKey { - static var defaultValue: DB { DB.main } -} - struct NodeServiceKey: EnvironmentKey { static var defaultValue: NodeService { NodeService.main } } @@ -80,11 +76,6 @@ struct IsWalletPresentedServiceKey: EnvironmentKey { } extension EnvironmentValues { - var db: DB { - get { self[DatabaseQueueKey.self] } - set { self[DatabaseQueueKey.self] = newValue } - } - var nodeService: NodeService { get { self[NodeServiceKey.self] } set { self[NodeServiceKey.self] = newValue } diff --git a/Gem/Wallets/Scenes/WalletsScene.swift b/Gem/Wallets/Scenes/WalletsScene.swift index 212da21f..58d9179c 100644 --- a/Gem/Wallets/Scenes/WalletsScene.swift +++ b/Gem/Wallets/Scenes/WalletsScene.swift @@ -8,7 +8,6 @@ import Style struct WalletsScene: View { @Environment(\.dismiss) private var dismiss - @Environment(\.db) private var DB @Environment(\.keystore) private var keystore @State private var isPresentingErrorMessage: String? @@ -31,8 +30,8 @@ struct WalletsScene: View { model: WalletsViewModel ) { self.model = model - _pinnedWallets = Query(WalletsRequest(isPinned: true), in: \.db.dbQueue) - _wallets = Query(WalletsRequest(isPinned: false), in: \.db.dbQueue) + _pinnedWallets = Query(WalletsRequest(isPinned: true)) + _wallets = Query(WalletsRequest(isPinned: false)) } var body: some View { diff --git a/Packages/Store/Sources/Requests/AssetRequest.swift b/Packages/Store/Sources/Requests/AssetRequest.swift index bfe6efb8..5167f235 100644 --- a/Packages/Store/Sources/Requests/AssetRequest.swift +++ b/Packages/Store/Sources/Requests/AssetRequest.swift @@ -6,30 +6,20 @@ import GRDBQuery import Combine import Primitives -public struct AssetRequest: Queryable { - +public struct AssetRequest: ValueObservationQueryable { public static var defaultValue: AssetData { AssetData.empty } - public let walletId: String public var assetId: String - public init( - walletId: String, - assetId: String - ) { + private let walletId: String + + public init(walletId: String, assetId: String) { self.walletId = walletId self.assetId = assetId } - - public func publisher(in dbQueue: DatabaseQueue) -> AnyPublisher { - ValueObservation - .tracking { db in try fetch(db) } - .publisher(in: dbQueue, scheduling: .immediate) - .eraseToAnyPublisher() - } - - private func fetch(_ db: Database) throws -> AssetData { - return try AssetRecord + + public func fetch(_ db: Database) throws -> AssetData { + try AssetRecord .including(optional: AssetRecord.price) .including(optional: AssetRecord.balance) .including(optional: AssetRecord.details) @@ -43,7 +33,10 @@ public struct AssetRequest: Queryable { } } +// MARK: - Models Exttensions + //TODO: Find a way to remove .empty + extension AssetData { static let empty: AssetData = { return AssetData( diff --git a/Packages/Store/Sources/Requests/AssetsInfoRequest.swift b/Packages/Store/Sources/Requests/AssetsInfoRequest.swift index f1c67ed5..61991cd2 100644 --- a/Packages/Store/Sources/Requests/AssetsInfoRequest.swift +++ b/Packages/Store/Sources/Requests/AssetsInfoRequest.swift @@ -4,23 +4,16 @@ import GRDBQuery import Combine import Primitives -public struct AssetsInfoRequest: Queryable { +public struct AssetsInfoRequest: ValueObservationQueryable { public static var defaultValue: AssetsInfo { AssetsInfo(hidden: 0) } - let walletId: String - + private let walletId: String + public init(walletId: String) { self.walletId = walletId } - - public func publisher(in dbQueue: DatabaseQueue) -> AnyPublisher { - ValueObservation - .tracking { db in try fetch(db) } - .publisher(in: dbQueue, scheduling: .immediate) - .eraseToAnyPublisher() - } - - private func fetch(_ db: Database) throws -> AssetsInfo { + + public func fetch(_ db: Database) throws -> AssetsInfo { let hidden = try AssetBalanceRecord .filter(Columns.Balance.walletId == walletId) .filter(Columns.Balance.isHidden == true) diff --git a/Packages/Store/Sources/Requests/AssetsRequest.swift b/Packages/Store/Sources/Requests/AssetsRequest.swift index 86eb3f6e..1e65b7e6 100644 --- a/Packages/Store/Sources/Requests/AssetsRequest.swift +++ b/Packages/Store/Sources/Requests/AssetsRequest.swift @@ -4,13 +4,14 @@ import GRDBQuery import Combine import Primitives -public struct AssetsRequest: Queryable { +public struct AssetsRequest: ValueObservationQueryable { public static var defaultValue: [AssetData] { [] } - public var walletID: String + private let walletID: String + public var searchBy: String public var filters: [AssetsRequestFilter] - + public init( walletID: String, searchBy: String = "", @@ -20,42 +21,19 @@ public struct AssetsRequest: Queryable { self.searchBy = searchBy self.filters = filters } - - public func publisher(in dbQueue: DatabaseQueue) -> AnyPublisher<[AssetData], Error> { - ValueObservation - .tracking { db in try fetch(db) } - .publisher(in: dbQueue, scheduling: .immediate) - .map { $0.map{ $0 } } - .eraseToAnyPublisher() - } - - func assetBalancesRequest(_ db: Database) throws -> [AssetData] { - try fetchAssets(filters: filters) - .fetchAll(db).map { $0.assetData } - } - - func assetsRequest(_ db: Database, searchBy: String, excludeAssetIds: [String]) throws -> [AssetData] { - return try Self.fetchAssetsSearch( - walletId: walletID, - searchBy: searchBy, - filters: filters, - excludeAssetIds: excludeAssetIds - ) - .fetchAll(db).map { $0.assetData } - } - - private func fetch(_ db: Database) throws -> [AssetData] { + + public func fetch(_ db: Database) throws -> [AssetData] { let searchBy = searchBy.trim() + if filters.contains(.includeNewAssets) { let request1 = try assetBalancesRequest(db) let request2 = try assetsRequest(db, searchBy: searchBy, excludeAssetIds: request1.map { $0.asset.id.identifier }) - + return [request1, request2].flatMap { $0 } - } else { - return try assetBalancesRequest(db) } + return try assetBalancesRequest(db) } - + func fetchAssets(filters: [AssetsRequestFilter])-> QueryInterfaceRequest { var request = AssetRecord .including(optional: AssetRecord.price) @@ -71,14 +49,33 @@ public struct AssetsRequest: Queryable { if !searchBy.isEmpty { request = Self.applyFilter(request: request, .search(searchBy)) } - + filters.forEach { request = Self.applyFilter(request: request, $0) } return request.asRequest(of: AssetRecordInfo.self) } - - static func applyFilter(request: QueryInterfaceRequest, _ filter: AssetsRequestFilter) -> QueryInterfaceRequest { +} + +// MARK: - Private + +extension AssetsRequest { + private func assetBalancesRequest(_ db: Database) throws -> [AssetData] { + try fetchAssets(filters: filters) + .fetchAll(db).map { $0.assetData } + } + + private func assetsRequest(_ db: Database, searchBy: String, excludeAssetIds: [String]) throws -> [AssetData] { + try Self.fetchAssetsSearch( + walletId: walletID, + searchBy: searchBy, + filters: filters, + excludeAssetIds: excludeAssetIds + ) + .fetchAll(db).map { $0.assetData } + } + + static private func applyFilter(request: QueryInterfaceRequest, _ filter: AssetsRequestFilter) -> QueryInterfaceRequest { switch filter { case .search(let name): return request @@ -136,8 +133,8 @@ public struct AssetsRequest: Queryable { return request } } - - static func fetchAssetsSearch( + + static private func fetchAssetsSearch( walletId: String, searchBy: String, filters: [AssetsRequestFilter], @@ -151,7 +148,7 @@ public struct AssetsRequest: Queryable { ) .order(Columns.Asset.rank.asc) .limit(50) - + if !searchBy.isEmpty { request = Self.applyFilter(request: request, .search(searchBy)) } diff --git a/Packages/Store/Sources/Requests/BannerRequest.swift b/Packages/Store/Sources/Requests/BannerRequest.swift index 73b2a63d..7ee58800 100644 --- a/Packages/Store/Sources/Requests/BannerRequest.swift +++ b/Packages/Store/Sources/Requests/BannerRequest.swift @@ -4,14 +4,14 @@ import Foundation import GRDB import GRDBQuery import Combine -import Primitives +@preconcurrency import Primitives // TODO: - integrate Sendable for BannerEvent -public struct BannersRequest: Queryable { +public struct BannersRequest: ValueObservationQueryable { public static var defaultValue: [Banner] { [] } - let walletId: String? - let assetId: String? - let events: [BannerEvent] + private let walletId: String? + private let assetId: String? + private let events: [BannerEvent] public init( walletId: String?, @@ -23,16 +23,8 @@ public struct BannersRequest: Queryable { self.events = events } - public func publisher(in dbQueue: DatabaseQueue) -> AnyPublisher<[Banner], Error> { - ValueObservation - .tracking { db in try fetch(db) } - .publisher(in: dbQueue, scheduling: .immediate) - .map { $0.map{ $0 } } - .eraseToAnyPublisher() - } - - private func fetch(_ db: Database) throws -> [Banner] { - return try BannerRecord + public func fetch(_ db: Database) throws -> [Banner] { + try BannerRecord .including(optional: BannerRecord.asset) .including(optional: BannerRecord.wallet) .filter(Columns.Banner.walletId == walletId || Columns.Banner.walletId == nil) diff --git a/Packages/Store/Sources/Requests/ConnectionsRequest.swift b/Packages/Store/Sources/Requests/ConnectionsRequest.swift index 9a414d75..23d3907f 100644 --- a/Packages/Store/Sources/Requests/ConnectionsRequest.swift +++ b/Packages/Store/Sources/Requests/ConnectionsRequest.swift @@ -6,22 +6,13 @@ import GRDBQuery import Combine import Primitives -public struct ConnectionsRequest: Queryable { +public struct ConnectionsRequest: ValueObservationQueryable { public static var defaultValue: [WalletConnection] { [] } - public init() { - } - - public func publisher(in dbQueue: DatabaseQueue) -> AnyPublisher<[WalletConnection], Error> { - ValueObservation - .tracking { db in try fetch(db) } - .publisher(in: dbQueue, scheduling: .immediate) - .map { $0.map{ $0 } } - .eraseToAnyPublisher() - } - - private func fetch(_ db: Database) throws -> [WalletConnection] { - return try WalletRecord + public init() {} + + public func fetch(_ db: Database) throws -> [WalletConnection] { + try WalletRecord .including(required: WalletRecord.connection) .asRequest(of: WalletConnectionInfo.self) .fetchAll(db) diff --git a/Packages/Store/Sources/Requests/StakeDelegationsRequest.swift b/Packages/Store/Sources/Requests/StakeDelegationsRequest.swift index ae4144cb..4592e9e6 100644 --- a/Packages/Store/Sources/Requests/StakeDelegationsRequest.swift +++ b/Packages/Store/Sources/Requests/StakeDelegationsRequest.swift @@ -6,27 +6,19 @@ import GRDBQuery import Combine import Primitives -public struct StakeDelegationsRequest: Queryable { +public struct StakeDelegationsRequest: ValueObservationQueryable { public static var defaultValue: [Delegation] { [] } - let walletId: String - let assetId: String - + private let walletId: String + private let assetId: String + public init(walletId: String, assetId: String) { self.walletId = walletId self.assetId = assetId } - - public func publisher(in dbQueue: DatabaseQueue) -> AnyPublisher<[Delegation], Error> { - ValueObservation - .tracking { db in try fetch(db) } - .publisher(in: dbQueue, scheduling: .immediate) - .map { $0.map{ $0 } } - .eraseToAnyPublisher() - } - - private func fetch(_ db: Database) throws -> [Delegation] { - return try StakeDelegationRecord + + public func fetch(_ db: Database) throws -> [Delegation] { + try StakeDelegationRecord .including(optional: StakeDelegationRecord.validator) .including(optional: StakeDelegationRecord.price) .filter(Columns.StakeDelegation.walletId == walletId) diff --git a/Packages/Store/Sources/Requests/TotalValueRequest.swift b/Packages/Store/Sources/Requests/TotalValueRequest.swift index 4320d0c5..67a5e2eb 100644 --- a/Packages/Store/Sources/Requests/TotalValueRequest.swift +++ b/Packages/Store/Sources/Requests/TotalValueRequest.swift @@ -4,29 +4,18 @@ import GRDBQuery import Combine import Primitives -public struct TotalValueRequest: Queryable { +public struct TotalValueRequest: ValueObservationQueryable { public static var defaultValue: Double { 0 } public var walletId: String - public init( - walletID: String - ) { + public init(walletID: String) { self.walletId = walletID } - - public func publisher(in dbQueue: DatabaseQueue) -> AnyPublisher { - ValueObservation - .tracking { db in try fetch(db) } - // The `.immediate` scheduling feeds the view right on subscription, - // and avoids an initial rendering with an empty list: - .publisher(in: dbQueue, scheduling: .immediate) - .eraseToAnyPublisher() - } - - private func fetch(_ db: Database) throws -> Double { - //TODO: Refactor to calculate total price - return try AssetRecord + + public func fetch(_ db: Database) throws -> Double { + //TODO: - Refactor to calculate total price + try AssetRecord .including(optional: AssetRecord.price) .including(optional: AssetRecord.balance) .joining(required: AssetRecord.balance diff --git a/Packages/Store/Sources/Requests/TransactionsCountRequest.swift b/Packages/Store/Sources/Requests/TransactionsCountRequest.swift index f030546c..298a7b36 100644 --- a/Packages/Store/Sources/Requests/TransactionsCountRequest.swift +++ b/Packages/Store/Sources/Requests/TransactionsCountRequest.swift @@ -4,9 +4,9 @@ import Foundation import GRDB import GRDBQuery import Combine -import Primitives +@preconcurrency import Primitives // TODO: - integrate Sendable for TransactionState -public struct TransactionsCountRequest: Queryable { +public struct TransactionsCountRequest: ValueObservationQueryable { public static var defaultValue: Int { 0 } private let walletId: String @@ -20,15 +20,8 @@ public struct TransactionsCountRequest: Queryable { self.state = state } - public func publisher(in dbQueue: DatabaseQueue) -> AnyPublisher { - ValueObservation - .tracking { db in try fetch(db) } - .publisher(in: dbQueue, scheduling: .immediate) - .eraseToAnyPublisher() - } - - private func fetch(_ db: Database) throws -> Int { - return try TransactionRecord + public func fetch(_ db: Database) throws -> Int { + try TransactionRecord .filter(Columns.Transaction.walletId == walletId) .filter(Columns.Transaction.state == state.rawValue) .fetchCount(db) diff --git a/Packages/Store/Sources/Requests/TransactionsRequest.swift b/Packages/Store/Sources/Requests/TransactionsRequest.swift index 2ac8741b..65a37f84 100644 --- a/Packages/Store/Sources/Requests/TransactionsRequest.swift +++ b/Packages/Store/Sources/Requests/TransactionsRequest.swift @@ -6,13 +6,13 @@ import GRDBQuery import Combine import Primitives -public struct TransactionsRequest: Queryable { +public struct TransactionsRequest: ValueObservationQueryable { public static var defaultValue: [TransactionExtended] { [] } - - let walletId: String - let type: TransactionsRequestType - let limit: Int - + + private let walletId: String + private let type: TransactionsRequestType + private let limit: Int + public init( walletId: String, type: TransactionsRequestType, @@ -22,16 +22,8 @@ public struct TransactionsRequest: Queryable { self.type = type self.limit = limit } - - public func publisher(in dbQueue: DatabaseQueue) -> AnyPublisher<[TransactionExtended], Error> { - ValueObservation - .tracking { db in try fetch(db) } - .publisher(in: dbQueue, scheduling: .immediate) - .map { $0 } - .eraseToAnyPublisher() - } - - private func fetch(_ db: Database) throws -> [TransactionExtended] { + + public func fetch(_ db: Database) throws -> [TransactionExtended] { let states = states(type: type) let types = types(type: type) var request = TransactionRecord @@ -46,7 +38,7 @@ public struct TransactionsRequest: Queryable { .order(Columns.Transaction.date.desc) .distinct() .limit(limit) - + switch type { case .asset(let assetId): request = request.joining(required: TransactionRecord.assetsAssociation.filter(Columns.TransactionAssetAssociation.assetId == assetId.identifier)) @@ -57,29 +49,33 @@ public struct TransactionsRequest: Queryable { case .all, .pending: break } - + return try request.asRequest(of: TransactionInfo.self) .fetchAll(db) .compactMap { $0.mapToTransactionExtended() } } - +} + +// MARK: - Private + +extension TransactionsRequest { private func states(type: TransactionsRequestType) -> [String] { switch type { case .pending: - return [TransactionState.pending.rawValue] + [TransactionState.pending.rawValue] case .all, .asset, .transaction: - return TransactionState.allCases.map { $0.rawValue } + TransactionState.allCases.map { $0.rawValue } case .assetsTransactionType(_, _, let states): - return states.map { $0.rawValue } + states.map { $0.rawValue } } } - + private func types(type: TransactionsRequestType) -> [String] { switch type { case .assetsTransactionType(_, let type, _): - return [type.rawValue] + [type.rawValue] case .pending, .all, .asset, .transaction: - return TransactionType.allCases.map { $0.rawValue } + TransactionType.allCases.map { $0.rawValue } } } } diff --git a/Packages/Store/Sources/Requests/WalletRequest.swift b/Packages/Store/Sources/Requests/WalletRequest.swift index 6fc174ce..9837d89f 100644 --- a/Packages/Store/Sources/Requests/WalletRequest.swift +++ b/Packages/Store/Sources/Requests/WalletRequest.swift @@ -6,25 +6,17 @@ import GRDBQuery import Combine import Primitives -public struct WalletRequest: Queryable { +public struct WalletRequest: ValueObservationQueryable { public static var defaultValue: Wallet? { .none } - - let walletId: String - + + private let walletId: String + public init(walletId: String) { self.walletId = walletId } - - public func publisher(in dbQueue: DatabaseQueue) -> AnyPublisher { - ValueObservation - .tracking { db in try fetch(db) } - .publisher(in: dbQueue, scheduling: .immediate) - .map { $0.map{ $0 } } - .eraseToAnyPublisher() - } - - private func fetch(_ db: Database) throws -> Wallet? { - return try WalletRecord + + public func fetch(_ db: Database) throws -> Wallet? { + try WalletRecord .including(all: WalletRecord.accounts) .asRequest(of: WalletRecordInfo.self) .filter(Columns.Wallet.id == walletId) diff --git a/Packages/Store/Sources/Requests/WalletsRequest.swift b/Packages/Store/Sources/Requests/WalletsRequest.swift index a1503c62..ed298de8 100644 --- a/Packages/Store/Sources/Requests/WalletsRequest.swift +++ b/Packages/Store/Sources/Requests/WalletsRequest.swift @@ -6,26 +6,17 @@ import GRDBQuery import Combine import Primitives -public struct WalletsRequest: Queryable { +public struct WalletsRequest: ValueObservationQueryable { public static var defaultValue: [Wallet] { [] } private let isPinned: Bool - public init( - isPinned: Bool - ) { - self.isPinned = isPinned - } - public func publisher(in dbQueue: DatabaseQueue) -> AnyPublisher<[Wallet], Error> { - ValueObservation - .tracking { db in try fetch(db) } - .publisher(in: dbQueue, scheduling: .immediate) - .map { $0.map{ $0 } } - .eraseToAnyPublisher() + public init(isPinned: Bool) { + self.isPinned = isPinned } - private func fetch(_ db: Database) throws -> [Wallet] { - return try WalletRecord + public func fetch(_ db: Database) throws -> [Wallet] { + try WalletRecord .including(all: WalletRecord.accounts) .filter(Columns.Wallet.isPinned == isPinned) .order(Columns.Wallet.order.asc) diff --git a/Packages/Store/Sources/Types/AssetsRequestFilter.swift b/Packages/Store/Sources/Types/AssetsRequestFilter.swift index 4055d55e..f0cec35a 100644 --- a/Packages/Store/Sources/Types/AssetsRequestFilter.swift +++ b/Packages/Store/Sources/Types/AssetsRequestFilter.swift @@ -19,3 +19,4 @@ public enum AssetsRequestFilter { } extension AssetsRequestFilter: Equatable {} +extension AssetsRequestFilter: Sendable {} diff --git a/Packages/Store/Sources/Types/TransactionsRequestType.swift b/Packages/Store/Sources/Types/TransactionsRequestType.swift index cddbcf2f..9c3f3a45 100644 --- a/Packages/Store/Sources/Types/TransactionsRequestType.swift +++ b/Packages/Store/Sources/Types/TransactionsRequestType.swift @@ -1,7 +1,7 @@ // Copyright (c). Gem Wallet. All rights reserved. import Foundation -import Primitives +@preconcurrency import Primitives // TODO: - integrate Sendable for AssetId & TransactionType & TransactionState public enum TransactionsRequestType: Equatable { case all @@ -23,3 +23,5 @@ extension TransactionsRequestType: Identifiable { } } } + +extension TransactionsRequestType: Sendable {} diff --git a/core b/core index f4348e62..4a75f6af 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit f4348e62d354b4530eccdf656a393d885feeea94 +Subproject commit 4a75f6af2b7e6592c5bfc84976dbe54c023e3a08