-
Notifications
You must be signed in to change notification settings - Fork 121
[Local Catalog] Incremental sync: persist incrementally changed products/variations to storage #16106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Local Catalog] Incremental sync: persist incrementally changed products/variations to storage #16106
Changes from all commits
7b8d7d2
da8ada9
6e2a3d6
cdd580d
7dbd5b3
7b37191
20b5910
7162e20
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,20 @@ | ||
| // periphery:ignore:all | ||
| import Foundation | ||
| import Storage | ||
| import GRDB | ||
|
|
||
| protocol POSCatalogPersistenceServiceProtocol { | ||
| /// Clears existing data and persists new catalog data | ||
| /// - Parameters: | ||
| /// - catalog: The catalog to persist | ||
| /// - siteID: The site ID to associate the catalog with | ||
| func replaceAllCatalogData(_ catalog: POSCatalog, siteID: Int64) async throws | ||
|
|
||
| /// Persists incremental catalog data (insert/update) | ||
| /// - Parameters: | ||
| /// - catalog: The catalog difference to persist | ||
| /// - siteID: The site ID to associate the catalog with | ||
| func persistIncrementalCatalogData(_ catalog: POSCatalog, siteID: Int64) async throws | ||
| } | ||
|
|
||
| final class POSCatalogPersistenceService: POSCatalogPersistenceServiceProtocol { | ||
|
|
@@ -29,23 +36,23 @@ final class POSCatalogPersistenceService: POSCatalogPersistenceServiceProtocol { | |
| try site.insert(db) | ||
|
|
||
| for product in catalog.productsToPersist { | ||
| try product.insert(db, onConflict: .ignore) | ||
| try product.insert(db, onConflict: .replace) | ||
| } | ||
|
|
||
| for image in catalog.productImagesToPersist { | ||
| try image.insert(db, onConflict: .ignore) | ||
| try image.insert(db, onConflict: .replace) | ||
| } | ||
|
|
||
| for var attribute in catalog.productAttributesToPersist { | ||
| try attribute.insert(db) | ||
| } | ||
|
|
||
| for variation in catalog.variationsToPersist { | ||
| try variation.insert(db, onConflict: .ignore) | ||
| try variation.insert(db, onConflict: .replace) | ||
| } | ||
|
|
||
| for image in catalog.variationImagesToPersist { | ||
| try image.insert(db, onConflict: .ignore) | ||
| try image.insert(db, onConflict: .replace) | ||
| } | ||
|
|
||
| for var attribute in catalog.variationAttributesToPersist { | ||
|
|
@@ -68,6 +75,67 @@ final class POSCatalogPersistenceService: POSCatalogPersistenceServiceProtocol { | |
| "\(variationImageCount) variation images, \(variationAttributeCount) variation attributes") | ||
| } | ||
| } | ||
|
|
||
| func persistIncrementalCatalogData(_ catalog: POSCatalog, siteID: Int64) async throws { | ||
| DDLogInfo("💾 Persisting incremental catalog with \(catalog.products.count) products and \(catalog.variations.count) variations") | ||
|
|
||
| try await grdbManager.databaseConnection.write { db in | ||
| for product in catalog.productsToPersist { | ||
| try product.insert(db, onConflict: .replace) | ||
|
|
||
| try PersistedProductImage | ||
| .filter { $0.productID == product.id } | ||
| .deleteAll(db) | ||
|
|
||
| try PersistedProductAttribute | ||
| .filter { $0.productID == product.id } | ||
| .deleteAll(db) | ||
| } | ||
|
|
||
| for image in catalog.productImagesToPersist { | ||
| try image.insert(db, onConflict: .replace) | ||
| } | ||
|
|
||
| for var attribute in catalog.productAttributesToPersist { | ||
| try attribute.insert(db, onConflict: .replace) | ||
| } | ||
|
|
||
| for variation in catalog.variationsToPersist { | ||
| try variation.insert(db, onConflict: .replace) | ||
|
|
||
| try PersistedProductVariationImage | ||
| .filter { $0.productVariationID == variation.id } | ||
| .deleteAll(db) | ||
|
|
||
| try PersistedProductVariationAttribute | ||
| .filter { $0.productVariationID == variation.id } | ||
| .deleteAll(db) | ||
| } | ||
|
|
||
| for image in catalog.variationImagesToPersist { | ||
| try image.insert(db, onConflict: .replace) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the full sync, I used For variations on an incremental sync, it does matter because we'll definitely want to replace... so perhaps we should use replace everywhere?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea, incremental sync requires I replaced the |
||
| } | ||
|
|
||
| for var attribute in catalog.variationAttributesToPersist { | ||
| try attribute.insert(db, onConflict: .replace) | ||
| } | ||
| } | ||
|
|
||
| DDLogInfo("✅ Incremental catalog persistence complete") | ||
|
|
||
| try await grdbManager.databaseConnection.read { db in | ||
| let productCount = try PersistedProduct.fetchCount(db) | ||
| let productImageCount = try PersistedProductImage.fetchCount(db) | ||
| let productAttributeCount = try PersistedProductAttribute.fetchCount(db) | ||
| let variationCount = try PersistedProductVariation.fetchCount(db) | ||
| let variationImageCount = try PersistedProductVariationImage.fetchCount(db) | ||
| let variationAttributeCount = try PersistedProductVariationAttribute.fetchCount(db) | ||
|
|
||
| DDLogInfo("Total after incremental update: \(productCount) products, \(productImageCount) product images, " + | ||
| "\(productAttributeCount) product attributes, \(variationCount) variations, " + | ||
| "\(variationImageCount) variation images, \(variationAttributeCount) variation attributes") | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private extension POSCatalog { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can make all these public but I'll do it in a future PR.
I'm sure that periphery would moan about it, but actually it's part of the public interface for the persisted classes. Since the error messages are unclear, it's a better experience to make them public ahead of use.