Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Modules/Sources/Fakes/Yosemite.generated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ extension Yosemite.POSSimpleProduct {
)
}
}
extension Yosemite.POSSite {
/// Returns a "ready to use" type filled with fake values.
///
public static func fake() -> Yosemite.POSSite {
.init(
siteID: .fake(),
lastIncrementalSyncDate: .fake()
)
}
}
extension Yosemite.ProductReviewFromNoteParcel {
/// Returns a "ready to use" type filled with fake values.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct V001InitialSchema {
static func createSiteTable(_ db: Database) throws {
try db.create(table: "site") { siteTable in
siteTable.primaryKey("id", .integer).notNull()
siteTable.column("lastCatalogIncrementalSyncDate", .datetime)
}
}

Expand Down
8 changes: 7 additions & 1 deletion Modules/Sources/Storage/GRDB/Model/PersistedSite.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import GRDB
public struct PersistedSite: Codable {
// periphery:ignore - TODO: remove ignore when populating database
public let id: Int64
// periphery:ignore - TODO: remove ignore when populating database
public let lastCatalogIncrementalSyncDate: Date?

// periphery:ignore - TODO: remove ignore when populating database
public init(id: Int64) {
public init(id: Int64, lastCatalogIncrementalSyncDate: Date? = nil) {
self.id = id
self.lastCatalogIncrementalSyncDate = lastCatalogIncrementalSyncDate
}
}

Expand All @@ -19,12 +22,15 @@ extension PersistedSite: FetchableRecord, PersistableRecord {
public enum Columns {
// periphery:ignore - TODO: remove ignore when populating database
static let id = Column(CodingKeys.id)
// periphery:ignore - TODO: remove ignore when populating database
static let lastCatalogIncrementalSyncDate = Column(CodingKeys.lastCatalogIncrementalSyncDate)
}
}

// periphery:ignore - TODO: remove ignore when populating database
private extension PersistedSite {
enum CodingKeys: String, CodingKey {
case id
case lastCatalogIncrementalSyncDate
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ extension Yosemite.POSSimpleProduct {
}
}

extension Yosemite.POSSite {
public func copy(
siteID: CopiableProp<Int64> = .copy,
lastIncrementalSyncDate: NullableCopiableProp<Date> = .copy
) -> Yosemite.POSSite {
let siteID = siteID ?? self.siteID
let lastIncrementalSyncDate = lastIncrementalSyncDate ?? self.lastIncrementalSyncDate

return Yosemite.POSSite(
siteID: siteID,
lastIncrementalSyncDate: lastIncrementalSyncDate
)
}
}

extension Yosemite.ProductReviewFromNoteParcel {
public func copy(
note: CopiableProp<Note> = .copy,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Foundation
import Storage

extension PersistedSite {
init(from posSite: POSSite) {
self.init(
id: posSite.siteID,
lastCatalogIncrementalSyncDate: posSite.lastIncrementalSyncDate
)
}

func toPOSSite() -> POSSite {
POSSite(
siteID: id,
lastIncrementalSyncDate: lastCatalogIncrementalSyncDate
)
}
}
13 changes: 13 additions & 0 deletions Modules/Sources/Yosemite/PointOfSale/POSSite.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// periphery:ignore:all
import Codegen
import Foundation

public struct POSSite: Equatable, GeneratedCopiable, GeneratedFakeable {
public let siteID: Int64
public let lastIncrementalSyncDate: Date?

public init(siteID: Int64, lastIncrementalSyncDate: Date? = nil) {
self.siteID = siteID
self.lastIncrementalSyncDate = lastIncrementalSyncDate
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ public final class POSCatalogIncrementalSyncService: POSCatalogIncrementalSyncSe
private let syncRemote: POSCatalogSyncRemoteProtocol
private let batchSize: Int
private let persistenceService: POSCatalogPersistenceServiceProtocol
private var lastIncrementalSyncDates: [Int64: Date] = [:]
private let batchedLoader: BatchedRequestLoader

public convenience init?(credentials: Credentials?, batchSize: Int = 1, grdbManager: GRDBManagerProtocol) {
Expand All @@ -45,7 +44,7 @@ public final class POSCatalogIncrementalSyncService: POSCatalogIncrementalSyncSe
// MARK: - Protocol Conformance

public func startIncrementalSync(for siteID: Int64, lastFullSyncDate: Date) async throws {
let modifiedAfter = lastIncrementalSyncDates[siteID] ?? lastFullSyncDate
let modifiedAfter = try await latestSyncDate(siteID: siteID, lastFullSyncDate: lastFullSyncDate)

DDLogInfo("🔄 Starting incremental catalog sync for site ID: \(siteID), modifiedAfter: \(modifiedAfter)")

Expand All @@ -57,8 +56,7 @@ public final class POSCatalogIncrementalSyncService: POSCatalogIncrementalSyncSe
try await persistenceService.persistIncrementalCatalogData(catalog, siteID: siteID)
DDLogInfo("✅ Persisted \(catalog.products.count) products and \(catalog.variations.count) variations to database for siteID \(siteID)")

// TODO: WOOMOB-1289 - replace with store settings persistence
lastIncrementalSyncDates[siteID] = syncStartDate
try await persistenceService.updateSite(.init(siteID: siteID, lastIncrementalSyncDate: syncStartDate))
DDLogInfo("✅ Updated last incremental sync date to \(syncStartDate) for siteID \(siteID)")
} catch {
DDLogError("❌ Failed to sync and persist catalog incrementally: \(error)")
Expand Down Expand Up @@ -86,3 +84,11 @@ private extension POSCatalogIncrementalSyncService {
return POSCatalog(products: products, variations: variations)
}
}

// MARK: - Sync date

private extension POSCatalogIncrementalSyncService {
func latestSyncDate(siteID: Int64, lastFullSyncDate: Date) async throws -> Date {
try await persistenceService.loadSite(siteID: siteID)?.lastIncrementalSyncDate ?? lastFullSyncDate
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import Foundation
import Storage
import GRDB

enum POSCatalogPersistenceError: Error, Equatable {
case siteNotFound(siteID: Int64)
}

protocol POSCatalogPersistenceServiceProtocol {
/// Clears existing data and persists new catalog data
/// - Parameters:
Expand All @@ -15,6 +19,15 @@ protocol POSCatalogPersistenceServiceProtocol {
/// - catalog: The catalog difference to persist
/// - siteID: The site ID to associate the catalog with
func persistIncrementalCatalogData(_ catalog: POSCatalog, siteID: Int64) async throws

/// Loads the POS site for the given site ID
/// - Parameter siteID: The site ID to load the POSSite for
/// - Returns: The loaded POSSite or nil if not found in storage
func loadSite(siteID: Int64) async throws -> POSSite?

/// Updates the PersistedSite based on POSSite data
/// - Parameter site: The POSSite containing the updated data
func updateSite(_ site: POSSite) async throws
}

final class POSCatalogPersistenceService: POSCatalogPersistenceServiceProtocol {
Expand Down Expand Up @@ -136,6 +149,23 @@ final class POSCatalogPersistenceService: POSCatalogPersistenceServiceProtocol {
"\(variationImageCount) variation images, \(variationAttributeCount) variation attributes")
}
}

func loadSite(siteID: Int64) async throws -> POSSite? {
try await grdbManager.databaseConnection.read { db in
try PersistedSite.filter(key: siteID).fetchOne(db)?.toPOSSite()
}
}

func updateSite(_ site: POSSite) async throws {
try await grdbManager.databaseConnection.write { db in
guard try PersistedSite.filter(key: site.siteID).fetchOne(db) != nil else {
throw POSCatalogPersistenceError.siteNotFound(siteID: site.siteID)
}

let persistedSite = PersistedSite(from: site)
try persistedSite.update(db)
Comment on lines +165 to +166
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps PersistedSite needs MutableFetchableRecord?

Seems a little odd to fetch the site and never use it, just replace it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems a little odd to fetch the site and never use it, just replace it.

Did you mean fetching the site from the database? L167 is converting a POSSite to PersistedSite without going through the database.

These two lines are to update the Site in the database from a given POSSite. Feel free to share better ways to do update an existing record.

}
}
}

private extension POSCatalog {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,8 @@ private final class MockPOSCatalogPersistenceService: POSCatalogPersistenceServi
}

func persistIncrementalCatalogData(_ catalog: POSCatalog, siteID: Int64) async throws {}

func loadSite(siteID: Int64) async throws -> POSSite? { nil }

func updateSite(_ site: POSSite) async throws {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ private final class MockPOSCatalogPersistenceService: POSCatalogPersistenceServi
private(set) var persistIncrementalCatalogDataLastPersistedSiteID: Int64?
var persistIncrementalCatalogDataError: Error?

private var storedSites: [Int64: POSSite] = [:]

func replaceAllCatalogData(_ catalog: POSCatalog, siteID: Int64) async throws {}

func persistIncrementalCatalogData(_ catalog: POSCatalog, siteID: Int64) async throws {
Expand All @@ -193,4 +195,12 @@ private final class MockPOSCatalogPersistenceService: POSCatalogPersistenceServi
throw error
}
}

func loadSite(siteID: Int64) async throws -> POSSite? {
storedSites[siteID]
}

func updateSite(_ site: POSSite) async throws {
storedSites[site.siteID] = site
}
}
Loading