Skip to content

Commit e042f78

Browse files
committed
Add OrderAction.observeInsertedOrders for observing locally inserted orders.
1 parent f4df557 commit e042f78

File tree

3 files changed

+146
-1
lines changed

3 files changed

+146
-1
lines changed

Yosemite/Yosemite/Actions/OrderAction.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Combine
12
import Foundation
23
import Networking
34

@@ -98,4 +99,8 @@ public enum OrderAction: Action {
9899
/// Deletes a given order.
99100
///
100101
case deleteOrder(siteID: Int64, order: Order, deletePermanently: Bool, onCompletion: (Result<Order, Error>) -> Void)
102+
103+
/// Returns a publisher that emits inserted orders on the view storage context.
104+
///
105+
case observeInsertedOrders(siteID: Int64, completion: (AnyPublisher<[Order], Never>) -> Void)
101106
}

Yosemite/Yosemite/Stores/OrderStore.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Combine
12
import Foundation
23
import Networking
34
import Storage
@@ -82,6 +83,8 @@ public class OrderStore: Store {
8283
markOrderAsPaidLocally(siteID: siteID, orderID: orderID, datePaid: datePaid, onCompletion: onCompletion)
8384
case let .deleteOrder(siteID, order, deletePermanently, onCompletion):
8485
deleteOrder(siteID: siteID, order: order, deletePermanently: deletePermanently, onCompletion: onCompletion)
86+
case let .observeInsertedOrders(siteID, completion):
87+
observeInsertedOrders(siteID: siteID, completion: completion)
8588
}
8689
}
8790
}
@@ -451,6 +454,26 @@ private extension OrderStore {
451454
}
452455
}
453456
}
457+
458+
func observeInsertedOrders(siteID: Int64, completion: (AnyPublisher<[Order], Never>) -> Void) {
459+
completion(
460+
NotificationCenter.default
461+
.publisher(for: .NSManagedObjectContextObjectsDidChange, object: storageManager.viewStorage)
462+
.map { notification -> [Order] in
463+
guard let note = ManagedObjectsDidChangeNotification(notification: notification) else {
464+
return []
465+
}
466+
467+
return note.insertedObjects.compactMap { ($0 as? StorageOrder)?.toReadOnly() }
468+
}
469+
.map { orders in
470+
orders.filter { $0.siteID == siteID }
471+
}
472+
.filter { $0.isEmpty == false }
473+
.removeDuplicates()
474+
.eraseToAnyPublisher()
475+
)
476+
}
454477
}
455478

456479

Yosemite/YosemiteTests/Stores/OrderStoreTests.swift

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Combine
12
import XCTest
23
@testable import Yosemite
34
@testable import Networking
@@ -46,7 +47,7 @@ final class OrderStoreTests: XCTestCase {
4647
///
4748
private let defaultSearchKeyword = "gooooooooogol"
4849

49-
50+
private var subscriptions: Set<AnyCancellable> = []
5051

5152
// MARK: - Overridden Methods
5253

@@ -1118,6 +1119,122 @@ final class OrderStoreTests: XCTestCase {
11181119
XCTAssertTrue(result.isFailure)
11191120
XCTAssertEqual(self.viewStorage.countObjects(ofType: Storage.Order.self), 0)
11201121
}
1122+
1123+
// MARK: - `observeInsertedOrders`
1124+
1125+
func test_observeInsertedOrders_emits_inserted_order() throws {
1126+
// Given
1127+
let store = OrderStore(dispatcher: dispatcher, storageManager: storageManager, network: network)
1128+
let siteID: Int64 = 6688
1129+
1130+
// Ensures the assertions take place after the Core Data notifications are sent.
1131+
var viewContextChanged = false
1132+
NotificationCenter.default
1133+
.publisher(for: .NSManagedObjectContextObjectsDidChange, object: viewStorage)
1134+
.sink { _ in
1135+
viewContextChanged = true
1136+
}.store(in: &subscriptions)
1137+
1138+
// When
1139+
let publisher: AnyPublisher<[Yosemite.Order], Never> = waitFor { promise in
1140+
let action = OrderAction.observeInsertedOrders(siteID: siteID) { publisher in
1141+
promise(publisher)
1142+
}
1143+
store.onAction(action)
1144+
}
1145+
var ordersSequence = [[Yosemite.Order]]()
1146+
publisher.sink { orders in
1147+
ordersSequence.append(orders)
1148+
}.store(in: &subscriptions)
1149+
1150+
// Inserts an order on the same site.
1151+
let order = sampleOrder().copy(siteID: siteID, status: .autoDraft)
1152+
store.upsertStoredOrder(readOnlyOrder: order, in: viewStorage)
1153+
1154+
waitUntil {
1155+
viewContextChanged == true
1156+
}
1157+
1158+
// Then
1159+
XCTAssertEqual(ordersSequence.count, 1)
1160+
XCTAssertEqual(ordersSequence.first, [order])
1161+
}
1162+
1163+
func test_observeInsertedOrders_does_not_emit_values_after_inserting_orders_in_a_different_site() throws {
1164+
// Given
1165+
let store = OrderStore(dispatcher: dispatcher, storageManager: storageManager, network: network)
1166+
let siteID: Int64 = 6688
1167+
let anotherSiteID: Int64 = 7799
1168+
1169+
// Ensures the assertions take place after the Core Data notifications are sent.
1170+
var viewContextChanged = false
1171+
NotificationCenter.default
1172+
.publisher(for: .NSManagedObjectContextObjectsDidChange, object: viewStorage)
1173+
.sink { _ in
1174+
viewContextChanged = true
1175+
}.store(in: &subscriptions)
1176+
1177+
// When
1178+
let publisher: AnyPublisher<[Yosemite.Order], Never> = waitFor { promise in
1179+
let action = OrderAction.observeInsertedOrders(siteID: siteID) { publisher in
1180+
promise(publisher)
1181+
}
1182+
store.onAction(action)
1183+
}
1184+
var ordersSequence = [[Yosemite.Order]]()
1185+
publisher.sink { orders in
1186+
ordersSequence.append(orders)
1187+
}.store(in: &subscriptions)
1188+
1189+
// Inserts an order on another site.
1190+
let order = sampleOrder().copy(siteID: anotherSiteID, status: .autoDraft)
1191+
store.upsertStoredOrder(readOnlyOrder: order, in: viewStorage)
1192+
1193+
waitUntil {
1194+
viewContextChanged == true
1195+
}
1196+
1197+
// Then
1198+
XCTAssertEqual(ordersSequence.count, 0)
1199+
}
1200+
1201+
func test_observeInsertedOrders_does_not_emit_values_after_inserting_a_non_order_object() throws {
1202+
// Given
1203+
let store = OrderStore(dispatcher: dispatcher, storageManager: storageManager, network: network)
1204+
let siteID: Int64 = 6688
1205+
1206+
// Ensures the assertions take place after the Core Data notifications are sent.
1207+
var viewContextChanged = false
1208+
NotificationCenter.default
1209+
.publisher(for: .NSManagedObjectContextObjectsDidChange, object: viewStorage)
1210+
.sink { _ in
1211+
viewContextChanged = true
1212+
}.store(in: &subscriptions)
1213+
1214+
// When
1215+
let publisher: AnyPublisher<[Yosemite.Order], Never> = waitFor { promise in
1216+
let action = OrderAction.observeInsertedOrders(siteID: siteID) { publisher in
1217+
promise(publisher)
1218+
}
1219+
store.onAction(action)
1220+
}
1221+
var ordersSequence = [[Yosemite.Order]]()
1222+
publisher.sink { orders in
1223+
ordersSequence.append(orders)
1224+
}.store(in: &subscriptions)
1225+
1226+
// Inserts a product on the same site.
1227+
let product = Product.fake().copy(siteID: siteID)
1228+
let storageProduct = viewStorage.insertNewObject(ofType: Storage.Product.self)
1229+
storageProduct.update(with: product)
1230+
1231+
waitUntil {
1232+
viewContextChanged == true
1233+
}
1234+
1235+
// Then
1236+
XCTAssertEqual(ordersSequence.count, 0)
1237+
}
11211238
}
11221239

11231240

0 commit comments

Comments
 (0)