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
40 changes: 20 additions & 20 deletions Modules/Sources/Storage/Model/MIGRATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,96 +238,96 @@ This file documents changes in the WCiOS Storage data model. Please explain any
- @rachelmcr 2022-12-15
- Added `SiteSummaryStats` entity.

## Model 79 (Release 11.7.0.0)
## Model 79 (Release 11.7.0.0) - Deleted
- @rachelmcr 2022-12-12
- Added `views` attribute to `SiteVisitStatsItem` entity.

## Model 78 (Release 11.4.0.0)
## Model 78 (Release 11.4.0.0) - Deleted
- @rachelmcr 2022-11-18
- Added `averageOrderValue` attribute to `OrderStatsV4Totals` entity.

## Model 77 (Release 11.2.0.0)
## Model 77 (Release 11.2.0.0) - Deleted
- @ealeksandrov 2022-11-07
- Added `frameNonce` attribute to `Site` entity.

## Model 76 (Release 11.0.0.0)
## Model 76 (Release 11.0.0.0) - Deleted
- @ealeksandrov 2022-10-26
- Added `loginURL` attribute to `Site` entity.

## Model 75 (Release 10.9.0.0)
## Model 75 (Release 10.9.0.0) - Deleted
- @iamgabrielma 2022-10-17
- Added `siteID` attribute to `Customer` entity.
- Added `siteID` attribute to `CustomerSearchResult` entity.
- Added `keyword` attribute to `CustomerSearchResult` entity.
- Removed `customerID` attribute from `CustomerSearchResult` entity.
- Added `WooCommerceModelV74toV75` mapping model.

## Model 74 (Release 10.8.0.0)
## Model 74 (Release 10.8.0.0) - Deleted
- @iamgabrielma 2022-10-12
- Added `Customer` entity.
- Added `CustomerSearchResult` entity.

## Model 73 (Release 10.6.0.0)
## Model 73 (Release 10.6.0.0) - Deleted
- @jaclync 2022-09-14
- Added `filterKey` attribute to `ProductSearchResults` entity.

## Model 72 (Release 9.6.0.0)
## Model 72 (Release 9.6.0.0) - Deleted
- @joshheald 2022-08-19
- Added `instructions` attribute to `PaymentGateway` entity.

## Model 71 (Release 9.6.0.0)
## Model 71 (Release 9.6.0.0) - Deleted
- @rachelmcr 2022-07-07
- Added `OrderMetaData` entity.
- Added `customFields` to-many relationship from `Order` to `OrderMetaData`.

## Model 70 (Release 9.5.0.0)
## Model 70 (Release 9.5.0.0) - Deleted
- @toupper 2022-06-22
- Update `OrderItemRefund` entity to include the `refundedItemID` property.

## Model 69 (Release 9.4.0.0)
## Model 69 (Release 9.4.0.0) - Deleted
- @ecarrion 2022-06-08
- Update `Order` entity to include the `needsProcessing`, `needsPayment`, and `isEditable` properties.

## Model 68 (Release 9.2.0.0)
## Model 68 (Release 9.2.0.0) - Deleted
- @pmusolino 2022-05-05
- Update `Coupon` entity and make `usageLimit`, `usageLimitPerUser` and `limitUsageToXItems` properties as optional with default value equal to `null`.

## Model 67 (Release 8.9.0.0)
## Model 67 (Release 8.9.0.0) - Deleted
- @ecarrion 2022-04-06
- Update `Order` entity to include the `paymentURL` property.

## Model 66 (Release 8.8.0.0)
## Model 66 (Release 8.8.0.0) - Deleted
- @pmusolino 2022-03-09
- Update `Order`'s `items` relationship to be ordered.

## Model 65 (Release 8.6.0.0)
## Model 65 (Release 8.6.0.0) - Deleted
- @joshheald 2022-02-14
- Added `WCPayCharge` entity.
- Added `WCPayCardPresentPaymentDetails` entity.
- Added `WCPayCardPaymentDetails` entity.
- Added `WCPayCardPresentReceiptDetails` entity.

## Model 64 (Release 8.6.0.0)
## Model 64 (Release 8.6.0.0) - Deleted
- @pmusolino 2022-02-09
- Added `InboxNote` entity.
- Added `InboxAction` entity.
- Added `actions` relationship from `InboxNote` to `[InboxAction]`.

## Model 63 (Release 8.5.0.0)
## Model 63 (Release 8.5.0.0) - Deleted
- @joshheald 2022-01-31
- Added `chargeID` attribute to `Order` entity.

## Model 62 (Release 8.5.0.0)
## Model 62 (Release 8.5.0.0) - Deleted
- @itsmeichigo 2022-01-25
- Added `CouponSearchResult` entity.
- Added `searchResults` relationship from `Coupon` to `CouponSearchResult`.

## Model 61 (Release 8.4.0.0)
## Model 61 (Release 8.4.0.0) - Deleted
- @selanthiraiyan 2022-01-13
- Added `OrderTaxLine` entity.
- Added `taxes` relationship from `Order` to `OrderTaxLine`.

## Model 60 (Release 8.3.0.0)
## Model 60 (Release 8.3.0.0) - Deleted
- @ecarrion 2021-12-22
- Added `OrderKey` attribute to `Order` entity.

Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,52 +24,52 @@ final class CoreDataIterativeMigrator_MigrationStepTests: XCTestCase {

func test_steps_returns_MigrationSteps_from_source_to_the_target_model() throws {
// Given
let modelVersion63 = ModelVersion(name: "Model 63")
let modelVersion71 = ModelVersion(name: "Model 71")
let sourceModel = try XCTUnwrap(modelsInventory.model(for: modelVersion63))
let targetModel = try XCTUnwrap(modelsInventory.model(for: modelVersion71))
let modelVersion83 = ModelVersion(name: "Model 83")
let modelVersion91 = ModelVersion(name: "Model 91")
let sourceModel = try XCTUnwrap(modelsInventory.model(for: modelVersion83))
let targetModel = try XCTUnwrap(modelsInventory.model(for: modelVersion91))

// When
let steps = try MigrationStep.steps(using: modelsInventory, source: sourceModel, target: targetModel)

// Then
// There should be 8 steps:
// - 63 to 64
// - 64 to 65
// - 65 to 66
// - 66 to 67
// - 67 to 68
// - 68 to 69
// - 69 to 70
// - 70 to 71
// - 83 to 84
// - 84 to 85
// - 85 to 86
// - 86 to 87
// - 87 to 88
// - 88 to 89
// - 89 to 90
// - 90 to 91
XCTAssertEqual(steps.count, 8)

// Assert the values of first and last steps.
let modelVersion64 = ModelVersion(name: "Model 64")
let modelVersion84 = ModelVersion(name: "Model 84")

let expectedFirstStep = MigrationStep(sourceVersion: modelVersion63,
sourceModel: try XCTUnwrap(modelsInventory.model(for: modelVersion63)),
targetVersion: modelVersion64,
targetModel: try XCTUnwrap(modelsInventory.model(for: modelVersion64)))
let expectedFirstStep = MigrationStep(sourceVersion: modelVersion83,
sourceModel: try XCTUnwrap(modelsInventory.model(for: modelVersion83)),
targetVersion: modelVersion84,
targetModel: try XCTUnwrap(modelsInventory.model(for: modelVersion84)))
let actualFirstStep = try XCTUnwrap(steps.first)
XCTAssertEqual(actualFirstStep, expectedFirstStep)

let modelVersion70 = ModelVersion(name: "Model 70")
let modelVersion90 = ModelVersion(name: "Model 90")

let expectedLastStep = MigrationStep(sourceVersion: modelVersion70,
sourceModel: try XCTUnwrap(modelsInventory.model(for: modelVersion70)),
targetVersion: modelVersion71,
targetModel: try XCTUnwrap(modelsInventory.model(for: modelVersion71)))
let expectedLastStep = MigrationStep(sourceVersion: modelVersion90,
sourceModel: try XCTUnwrap(modelsInventory.model(for: modelVersion90)),
targetVersion: modelVersion91,
targetModel: try XCTUnwrap(modelsInventory.model(for: modelVersion91)))
let actualLastStep = try XCTUnwrap(steps.last)
XCTAssertEqual(actualLastStep, expectedLastStep)
}

func test_steps_returns_one_MigrationStep_if_the_source_and_target_are_next_to_each_other() throws {
// Given
let sourceVersion = ModelVersion(name: "Model 67")
let sourceVersion = ModelVersion(name: "Model 87")
let sourceModel = try XCTUnwrap(modelsInventory.model(for: sourceVersion))

let targetVersion = ModelVersion(name: "Model 68")
let targetVersion = ModelVersion(name: "Model 88")
let targetModel = try XCTUnwrap(modelsInventory.model(for: targetVersion))

// When
Expand Down Expand Up @@ -140,23 +140,23 @@ final class CoreDataIterativeMigrator_MigrationStepTests: XCTestCase {
/// reach this condition because of the precondition checks in `CoreDataIterativeMigrator`.
func test_steps_returns_source_to_latest_version_MigrationSteps_if_the_source_and_target_are_the_same() throws {
// Given
let sourceModelName = "Model 67"
let sourceModelName = "Model 87"
let modelVersion37 = ModelVersion(name: sourceModelName)
let sourceModel = try XCTUnwrap(modelsInventory.model(for: modelVersion37))

// Find the index of Model 67 in the current inventory
// which only contains Models 60-124 as per latest update on https://github.com/woocommerce/woocommerce-ios/pull/15987
// Find the index of Model 87 in the current inventory
// which only contains Models 80-127 as per latest update on [https://github.com/woocommerce/woocommerce-ios/pull/16181]
let sourceModelIndex = try XCTUnwrap(modelsInventory.versions.firstIndex { $0.name == sourceModelName },
"Model 67 should exist in the inventory")
"Model 87 should exist in the inventory")
// When
let steps = try MigrationStep.steps(using: modelsInventory, source: sourceModel, target: sourceModel)

// Then
// Expected behavior (bug): When source == target, it returns steps from that model to the latest version
// This means: Model 67 → Model 68 → ... → Model 124
// This means: Model 87 → Model 88 → ... → Model 127
// Calculation: total versions - source index - 1 (since we don't include the source model itself)
let expectedStepCount = modelsInventory.versions.count - sourceModelIndex - 1
XCTAssertEqual(steps.count, expectedStepCount,
"Should return steps from Model 67 to the latest model (Model 124)")
"Should return steps from Model 87 to the latest model (Model 127)")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ final class CoreDataIterativeMigratorTests: XCTestCase {

func test_it_will_not_migrate_if_the_database_file_does_not_exist() throws {
// Given
let targetModel = try managedObjectModel(for: "Model 68")
let targetModel = try managedObjectModel(for: "Model 88")
let databaseURL = documentsDirectory.appendingPathComponent("database-file-that-does-not-exist")
let fileManager = MockFileManager()

Expand Down Expand Up @@ -139,36 +139,36 @@ final class CoreDataIterativeMigratorTests: XCTestCase {
/// files using the wrong `NSManagedObjectModel`.
func test_opening_a_store_with_a_different_model_fails() throws {
// Given
let model60 = try managedObjectModel(for: "Model 60")
let model70 = try managedObjectModel(for: "Model 70")
let model80 = try managedObjectModel(for: "Model 80")
let model90 = try managedObjectModel(for: "Model 90")

let storeURL = try urlForStore(withName: "Woo Test 30.sqlite", deleteIfExists: true)
let options = [NSInferMappingModelAutomaticallyOption: false, NSMigratePersistentStoresAutomaticallyOption: false]

// When
var psc = NSPersistentStoreCoordinator(managedObjectModel: model60)
var psc = NSPersistentStoreCoordinator(managedObjectModel: model80)
var ps = try? psc.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: options)

XCTAssertNotNil(ps)

try psc.remove(ps!)

// Load using a different model
psc = NSPersistentStoreCoordinator(managedObjectModel: model70)
psc = NSPersistentStoreCoordinator(managedObjectModel: model90)
ps = try? psc.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: options)

// When
XCTAssertNil(ps)
}

/// Test the IterativeMigrator can migrate iteratively between model 30 to 40.
func test_iterativeMigrate_can_iteratively_migrate_from_model_60_to_model_70() throws {
/// Test the IterativeMigrator can migrate iteratively between model 80 to 90.
func test_iterativeMigrate_can_iteratively_migrate_from_model_80_to_model_90() throws {
// Given
let storeType = NSSQLiteStoreType
let sourceModel = try managedObjectModel(for: "Model 60")
let targetModel = try managedObjectModel(for: "Model 70")
let sourceModel = try managedObjectModel(for: "Model 80")
let targetModel = try managedObjectModel(for: "Model 90")

let storeURL = try urlForStore(withName: "Woo Test 60.sqlite", deleteIfExists: true)
let storeURL = try urlForStore(withName: "Woo Test 80.sqlite", deleteIfExists: true)

let container = try startPersistentContainer(storeURL: storeURL, storeType: storeType, model: sourceModel)

Expand Down Expand Up @@ -206,17 +206,17 @@ final class CoreDataIterativeMigratorTests: XCTestCase {
func test_iterativeMigrate_replaces_the_original_SQLite_files() throws {
// Given
let storeType = NSSQLiteStoreType
let sourceModel = try managedObjectModel(for: "Model 61")
let targetModel = try managedObjectModel(for: "Model 62")
let sourceModel = try managedObjectModel(for: "Model 81")
let targetModel = try managedObjectModel(for: "Model 82")

let storeFileName = "Woo_Migration_Replacement_Unit_Test.sqlite"
let storeURL = try urlForStore(withName: storeFileName, deleteIfExists: true)

// Start a container so the SQLite files will be created.
let container = try startPersistentContainer(storeURL: storeURL, storeType: storeType, model: sourceModel)

// Precondition: `CouponSearchResult` should not exist in `Model 61` yet.
assertThat(container: container, hasNoEntity: "CouponSearchResult")
// Precondition: `ProductCompositeComponent` should not exist in `Model 81` yet.
assertThat(container: container, hasNoEntity: "ProductCompositeComponent")

let spyCoordinator = SpyPersistentStoreCoordinator(container.persistentStoreCoordinator)

Expand All @@ -239,14 +239,14 @@ final class CoreDataIterativeMigratorTests: XCTestCase {
XCTAssertEqual(replacement.sourceURL.deletingLastPathComponent(),
URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true))

// Assert that the same `storeURL` is using the new `Model 42`, which has the `OrderFeeLine` entity.
// Assert that the same `storeURL` is using the new `Model 82`, which has the `ProductCompositeComponent` entity.
let migratedContainer = try startPersistentContainer(storeURL: storeURL, storeType: storeType, model: targetModel)
assertThat(container: migratedContainer, hasEntity: "OrderFeeLine")
assertThat(container: migratedContainer, hasEntity: "ProductCompositeComponent")
}

func test_iterativeMigrate_will_not_migrate_if_the_database_and_the_model_are_compatible() throws {
// Given
let model = try managedObjectModel(for: "Model 68")
let model = try managedObjectModel(for: "Model 88")

// Start a container to create an existing database file.
let storeURL = try urlForStore(withName: "Woo_Compatibility_Test.sqlite", deleteIfExists: true)
Expand Down Expand Up @@ -275,14 +275,14 @@ final class CoreDataIterativeMigratorTests: XCTestCase {

func test_findSourceVersion_when_exists_then_returns_correct_version_for_existing_model() throws {
// Given
let targetVersion = ManagedObjectModelsInventory.ModelVersion(name: "Model 60")
let targetVersion = ManagedObjectModelsInventory.ModelVersion(name: "Model 80")
let targetModel = try XCTUnwrap(modelsInventory.model(for: targetVersion))

// When
let foundVersion = CoreDataMigratorUtils.findSourceVersion(for: targetModel, in: modelsInventory)

// Then
XCTAssertEqual(foundVersion?.name, "Model 60")
XCTAssertEqual(foundVersion?.name, "Model 80")
}

func test_findSourceVersion_when_unknown_model_then_returns_nil() throws {
Expand Down
20 changes: 10 additions & 10 deletions Modules/Tests/StorageTests/CoreData/CoreDataManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,8 @@ final class CoreDataManagerTests: XCTestCase {
// recreate the database.
let invalidModelsInventory = ManagedObjectModelsInventory(
packageURL: modelsInventory.packageURL,
currentModel: try XCTUnwrap(modelsInventory.model(for: .init(name: "Model 60"))),
versions: [.init(name: "Model 60")]
currentModel: try XCTUnwrap(modelsInventory.model(for: .init(name: "Model 80"))),
versions: [.init(name: "Model 80")]
)

manager = try makeManager(using: invalidModelsInventory, deletingExistingStoreFiles: false)
Expand All @@ -211,19 +211,19 @@ final class CoreDataManagerTests: XCTestCase {
insertAccount(to: manager.viewStorage)
XCTAssertEqual(manager.viewStorage.countObjects(ofType: Account.self), 2)

// The CouponSearchResult entity does not exist in Model 60, was introduced in Model 62
// This proves that the store was reset to Model 60.
XCTAssertNil(NSEntityDescription.entity(forEntityName: CouponSearchResult.entityName,
// The ProductCompositeComponent entity does not exist in Model 80, was introduced in Model 82
// This proves that the store was reset to Model 80.
XCTAssertNil(NSEntityDescription.entity(forEntityName: ProductCompositeComponent.entityName,
in: manager.viewStorage as! NSManagedObjectContext))
}

func test_accessing_persistentContainer_will_automatically_migrate_the_database() throws {
// Given
let modelsInventory = try makeModelsInventory()
// Create an inventory with up to Model 33 only. This is what we'll load first.
// Create an inventory with up to Model 83 only. This is what we'll load first.
let olderModelsInventory: ManagedObjectModelsInventory = try {
let model63Index = try XCTUnwrap(modelsInventory.versions.firstIndex(of: .init(name: "Model 63")))
let versions = Array(modelsInventory.versions.prefix(through: model63Index))
let model83Index = try XCTUnwrap(modelsInventory.versions.firstIndex(of: .init(name: "Model 83")))
let versions = Array(modelsInventory.versions.prefix(through: model83Index))

return ManagedObjectModelsInventory(
packageURL: modelsInventory.packageURL,
Expand All @@ -243,8 +243,8 @@ final class CoreDataManagerTests: XCTestCase {
}

XCTAssertEqual(manager.viewStorage.countObjects(ofType: Account.self), 1)
// The InboxNote entity does not exist in Model 63.
XCTAssertNil(NSEntityDescription.entity(forEntityName: InboxNote.entityName,
// The OrderItemProductAddOn entity does not exist in Model 83.
XCTAssertNil(NSEntityDescription.entity(forEntityName: OrderItemProductAddOn.entityName,
in: manager.viewStorage as! NSManagedObjectContext))

try assertThat(manager, isCompatibleWith: olderModelsInventory.currentModel)
Expand Down
Loading