diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/ui/stats/datasource/StatsRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/ui/stats/datasource/StatsRepository.kt index 48ef48ad53aa..61fd0e8632d0 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/ui/stats/datasource/StatsRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/ui/stats/datasource/StatsRepository.kt @@ -101,7 +101,6 @@ class StatsRepository @Inject constructor( result.granularity, result.quantity, result.date, - result.isCustomField ).let { Result.success(it.values.sum()) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/data/StatsRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/data/StatsRepository.kt index d6a6c04cc940..c4efb70a0828 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/data/StatsRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/data/StatsRepository.kt @@ -154,7 +154,6 @@ class StatsRepository @Inject constructor( result.granularity, result.quantity, result.date, - result.isCustomField ) } Result.success(visitorStats) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/dashboard/data/StatsRepositoryTests.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/dashboard/data/StatsRepositoryTests.kt index 86a4b53c3558..1c1dd1994761 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/dashboard/data/StatsRepositoryTests.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/dashboard/data/StatsRepositoryTests.kt @@ -68,12 +68,12 @@ class StatsRepositoryTests : BaseUnitTest() { fun `when visitors and revenue requests succeed then a success response is returned containing both value`() = testBlocking { val granularity = WCStatsStore.StatsGranularity.DAYS + val quantity = "5" val startDate = "2024-01-25 00:00:00" val endDate = "2024-01-25 23:59:59" val visitorStatsResponse = WCStatsStore.OnWCStatsChanged( - rowsAffected = 2, granularity = granularity, - quantity = "5", + quantity = quantity, date = startDate ) @@ -87,6 +87,8 @@ class StatsRepositoryTests : BaseUnitTest() { whenever(selectedSite.get()).thenReturn(defaultSiteModel) whenever(wooCommerceStore.getSiteSettings(any())).thenReturn(null) whenever(wcStatsStore.fetchNewVisitorStats(any())).thenReturn(visitorStatsResponse) + whenever(wcStatsStore.getNewVisitorStats(defaultSiteModel, granularity, quantity, startDate)) + .thenReturn(emptyMap()) whenever(wcStatsStore.fetchRevenueStats(any())).thenReturn(revenueStatsResponse) whenever(wcStatsStore.getRawRevenueStats(eq(defaultSiteModel), eq(granularity), eq(startDate), eq(endDate))) .thenReturn(WCRevenueStatsModel()) @@ -111,7 +113,7 @@ class StatsRepositoryTests : BaseUnitTest() { val granularity = WCStatsStore.StatsGranularity.DAYS val startDate = "2024-01-25 00:00:00" val endDate = "2024-01-25 23:59:59" - val visitorStatsResponse = WCStatsStore.OnWCStatsChanged(0, granularity).also { + val visitorStatsResponse = WCStatsStore.OnWCStatsChanged(granularity).also { it.error = WCStatsStore.OrderStatsError() it.causeOfChange = WCStatsAction.FETCH_NEW_VISITOR_STATS } @@ -150,7 +152,6 @@ class StatsRepositoryTests : BaseUnitTest() { val granularity = WCStatsStore.StatsGranularity.DAYS val startDate = "2024-01-25 00:00:00" val visitorStatsResponse = WCStatsStore.OnWCStatsChanged( - rowsAffected = 2, granularity = granularity, quantity = "5", date = startDate diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 68c56775e897..47a13c5023e2 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -2271,21 +2271,6 @@ UnitTestNamingRule:WCShippingLabelStoreTest.kt$WCShippingLabelStoreTest$@Test fun `verify shipping address`() UnitTestNamingRule:WCStatsSqlUtilsTest.kt$WCStatsSqlUtilsTest$@Test @Suppress("LongMethod") fun testGetRawRevenueStatsForSiteAndUnit() UnitTestNamingRule:WCStatsSqlUtilsTest.kt$WCStatsSqlUtilsTest$@Test @Suppress("LongMethod") fun testSimpleInsertionAndRetrievalOfRevenueStats() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Suppress("LongMethod") @Test fun testGetQuantityForMonths() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Suppress("LongMethod") @Test fun testGetQuantityForWeeks() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Suppress("LongMethod") @Test fun testGetQuantityForYears() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Test @Suppress("LongMethod") fun testGetRevenueAndOrderStatsForSite() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Test @Suppress("LongMethod") fun testGetVisitorStatsForCurrentDayGranularity() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Test @Suppress("LongMethod") fun testGetVisitorStatsForThisWeekGranularity() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Test fun testFailedFetchingVisitorSummaryStats() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Test fun testFetchBundlesErrorResponse() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Test fun testFetchBundlesNullResponse() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Test fun testFetchBundlesSuccessResponse() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Test fun testFetchCurrentDayRevenueStatsDate() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Test fun testFetchCurrentDayRevenueStatsDateSpecificEndDate() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Test fun testGetNewVisitorStatsWithInvalidData() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Test fun testGetQuantityForDays() - UnitTestNamingRule:WCStatsStoreTest.kt$WCStatsStoreTest$@Test fun testSuccessfulFetchingVisitorSummaryStats() UnitTestNamingRule:WCTaxStoreTest.kt$WCTaxStoreTest$@Test fun `get stored tax class list for site`() UnitTestNamingRule:WCUserStoreTest.kt$WCUserStoreTest$@Test fun `fetch user role`() UnitTestNamingRule:WCUserStoreTest.kt$WCUserStoreTest$@Test fun `get user role from db`() diff --git a/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/65.json b/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/65.json new file mode 100644 index 000000000000..86eb84b17444 --- /dev/null +++ b/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/65.json @@ -0,0 +1,3958 @@ +{ + "formatVersion": 1, + "database": { + "version": 65, + "identityHash": "2d180f4d4c2ccaf6305a746959d1289d", + "entities": [ + { + "tableName": "AddonEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`addonLocalId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `globalGroupLocalId` INTEGER, `productRemoteId` INTEGER, `localSiteId` INTEGER, `type` TEXT NOT NULL, `display` TEXT, `name` TEXT NOT NULL, `titleFormat` TEXT NOT NULL, `description` TEXT, `required` INTEGER NOT NULL, `position` INTEGER NOT NULL, `restrictions` TEXT, `priceType` TEXT, `price` TEXT, `min` INTEGER, `max` INTEGER, FOREIGN KEY(`globalGroupLocalId`) REFERENCES `GlobalAddonGroupEntity`(`globalGroupLocalId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "addonLocalId", + "columnName": "addonLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "globalGroupLocalId", + "columnName": "globalGroupLocalId", + "affinity": "INTEGER" + }, + { + "fieldPath": "productRemoteId", + "columnName": "productRemoteId", + "affinity": "INTEGER" + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "display", + "columnName": "display", + "affinity": "TEXT" + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "titleFormat", + "columnName": "titleFormat", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT" + }, + { + "fieldPath": "required", + "columnName": "required", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "restrictions", + "columnName": "restrictions", + "affinity": "TEXT" + }, + { + "fieldPath": "priceType", + "columnName": "priceType", + "affinity": "TEXT" + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT" + }, + { + "fieldPath": "min", + "columnName": "min", + "affinity": "INTEGER" + }, + { + "fieldPath": "max", + "columnName": "max", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "addonLocalId" + ] + }, + "indices": [ + { + "name": "index_AddonEntity_globalGroupLocalId", + "unique": false, + "columnNames": [ + "globalGroupLocalId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_AddonEntity_globalGroupLocalId` ON `${TABLE_NAME}` (`globalGroupLocalId`)" + } + ], + "foreignKeys": [ + { + "table": "GlobalAddonGroupEntity", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "globalGroupLocalId" + ], + "referencedColumns": [ + "globalGroupLocalId" + ] + } + ] + }, + { + "tableName": "AddonOptionEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`addonOptionLocalId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `addonLocalId` INTEGER NOT NULL, `priceType` TEXT NOT NULL, `label` TEXT, `price` TEXT, `image` TEXT, FOREIGN KEY(`addonLocalId`) REFERENCES `AddonEntity`(`addonLocalId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "addonOptionLocalId", + "columnName": "addonOptionLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addonLocalId", + "columnName": "addonLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "priceType", + "columnName": "priceType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT" + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT" + }, + { + "fieldPath": "image", + "columnName": "image", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "addonOptionLocalId" + ] + }, + "indices": [ + { + "name": "index_AddonOptionEntity_addonLocalId", + "unique": false, + "columnNames": [ + "addonLocalId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_AddonOptionEntity_addonLocalId` ON `${TABLE_NAME}` (`addonLocalId`)" + } + ], + "foreignKeys": [ + { + "table": "AddonEntity", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "addonLocalId" + ], + "referencedColumns": [ + "addonLocalId" + ] + } + ] + }, + { + "tableName": "Coupons", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `code` TEXT, `amount` TEXT, `dateCreated` TEXT, `dateCreatedGmt` TEXT, `dateModified` TEXT, `dateModifiedGmt` TEXT, `discountType` TEXT, `description` TEXT, `dateExpires` TEXT, `dateExpiresGmt` TEXT, `usageCount` INTEGER, `isForIndividualUse` INTEGER, `usageLimit` INTEGER, `usageLimitPerUser` INTEGER, `limitUsageToXItems` INTEGER, `isShippingFree` INTEGER, `areSaleItemsExcluded` INTEGER, `minimumAmount` TEXT, `maximumAmount` TEXT, `includedProductIds` TEXT, `excludedProductIds` TEXT, `includedCategoryIds` TEXT, `excludedCategoryIds` TEXT, PRIMARY KEY(`id`, `localSiteId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "code", + "columnName": "code", + "affinity": "TEXT" + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "TEXT" + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT" + }, + { + "fieldPath": "dateCreatedGmt", + "columnName": "dateCreatedGmt", + "affinity": "TEXT" + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT" + }, + { + "fieldPath": "dateModifiedGmt", + "columnName": "dateModifiedGmt", + "affinity": "TEXT" + }, + { + "fieldPath": "discountType", + "columnName": "discountType", + "affinity": "TEXT" + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT" + }, + { + "fieldPath": "dateExpires", + "columnName": "dateExpires", + "affinity": "TEXT" + }, + { + "fieldPath": "dateExpiresGmt", + "columnName": "dateExpiresGmt", + "affinity": "TEXT" + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER" + }, + { + "fieldPath": "isForIndividualUse", + "columnName": "isForIndividualUse", + "affinity": "INTEGER" + }, + { + "fieldPath": "usageLimit", + "columnName": "usageLimit", + "affinity": "INTEGER" + }, + { + "fieldPath": "usageLimitPerUser", + "columnName": "usageLimitPerUser", + "affinity": "INTEGER" + }, + { + "fieldPath": "limitUsageToXItems", + "columnName": "limitUsageToXItems", + "affinity": "INTEGER" + }, + { + "fieldPath": "isShippingFree", + "columnName": "isShippingFree", + "affinity": "INTEGER" + }, + { + "fieldPath": "areSaleItemsExcluded", + "columnName": "areSaleItemsExcluded", + "affinity": "INTEGER" + }, + { + "fieldPath": "minimumAmount", + "columnName": "minimumAmount", + "affinity": "TEXT" + }, + { + "fieldPath": "maximumAmount", + "columnName": "maximumAmount", + "affinity": "TEXT" + }, + { + "fieldPath": "includedProductIds", + "columnName": "includedProductIds", + "affinity": "TEXT" + }, + { + "fieldPath": "excludedProductIds", + "columnName": "excludedProductIds", + "affinity": "TEXT" + }, + { + "fieldPath": "includedCategoryIds", + "columnName": "includedCategoryIds", + "affinity": "TEXT" + }, + { + "fieldPath": "excludedCategoryIds", + "columnName": "excludedCategoryIds", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "localSiteId" + ] + } + }, + { + "tableName": "CouponEmails", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`couponId` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `email` TEXT NOT NULL, PRIMARY KEY(`couponId`, `localSiteId`, `email`), FOREIGN KEY(`couponId`, `localSiteId`) REFERENCES `Coupons`(`id`, `localSiteId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "couponId", + "columnName": "couponId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "couponId", + "localSiteId", + "email" + ] + }, + "foreignKeys": [ + { + "table": "Coupons", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "couponId", + "localSiteId" + ], + "referencedColumns": [ + "id", + "localSiteId" + ] + } + ] + }, + { + "tableName": "GlobalAddonGroupEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`globalGroupLocalId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `restrictedCategoriesIds` TEXT NOT NULL, `localSiteId` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "globalGroupLocalId", + "columnName": "globalGroupLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "restrictedCategoriesIds", + "columnName": "restrictedCategoriesIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "globalGroupLocalId" + ] + } + }, + { + "tableName": "OrderNotes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `noteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `dateCreated` TEXT, `note` TEXT, `author` TEXT, `isSystemNote` INTEGER NOT NULL, `isCustomerNote` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `noteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "noteId", + "columnName": "noteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT" + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT" + }, + { + "fieldPath": "author", + "columnName": "author", + "affinity": "TEXT" + }, + { + "fieldPath": "isSystemNote", + "columnName": "isSystemNote", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCustomerNote", + "columnName": "isCustomerNote", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "noteId" + ] + } + }, + { + "tableName": "OrderEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `number` TEXT NOT NULL, `status` TEXT NOT NULL, `currency` TEXT NOT NULL, `orderKey` TEXT NOT NULL, `dateCreated` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `total` TEXT NOT NULL, `totalTax` TEXT NOT NULL, `shippingTotal` TEXT NOT NULL, `paymentMethod` TEXT NOT NULL, `paymentMethodTitle` TEXT NOT NULL, `datePaid` TEXT NOT NULL, `pricesIncludeTax` INTEGER NOT NULL, `customerNote` TEXT NOT NULL, `discountTotal` TEXT NOT NULL, `discountCodes` TEXT NOT NULL, `refundTotal` TEXT NOT NULL, `customerId` INTEGER NOT NULL DEFAULT 0, `billingFirstName` TEXT NOT NULL, `billingLastName` TEXT NOT NULL, `billingCompany` TEXT NOT NULL, `billingAddress1` TEXT NOT NULL, `billingAddress2` TEXT NOT NULL, `billingCity` TEXT NOT NULL, `billingState` TEXT NOT NULL, `billingPostcode` TEXT NOT NULL, `billingCountry` TEXT NOT NULL, `billingEmail` TEXT NOT NULL, `billingPhone` TEXT NOT NULL, `shippingFirstName` TEXT NOT NULL, `shippingLastName` TEXT NOT NULL, `shippingCompany` TEXT NOT NULL, `shippingAddress1` TEXT NOT NULL, `shippingAddress2` TEXT NOT NULL, `shippingCity` TEXT NOT NULL, `shippingState` TEXT NOT NULL, `shippingPostcode` TEXT NOT NULL, `shippingCountry` TEXT NOT NULL, `shippingPhone` TEXT NOT NULL, `lineItems` TEXT NOT NULL, `shippingLines` TEXT NOT NULL, `feeLines` TEXT NOT NULL, `taxLines` TEXT NOT NULL, `couponLines` TEXT NOT NULL DEFAULT '', `metaData` TEXT NOT NULL, `paymentUrl` TEXT NOT NULL DEFAULT '', `isEditable` INTEGER NOT NULL DEFAULT 1, `needsPayment` INTEGER, `needsProcessing` INTEGER, `giftCardCode` TEXT NOT NULL DEFAULT '', `giftCardAmount` TEXT NOT NULL DEFAULT '', `shippingTax` TEXT NOT NULL DEFAULT '', `createdVia` TEXT NOT NULL DEFAULT '', PRIMARY KEY(`localSiteId`, `orderId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "orderKey", + "columnName": "orderKey", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "total", + "columnName": "total", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "totalTax", + "columnName": "totalTax", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingTotal", + "columnName": "shippingTotal", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "paymentMethod", + "columnName": "paymentMethod", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "paymentMethodTitle", + "columnName": "paymentMethodTitle", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "datePaid", + "columnName": "datePaid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pricesIncludeTax", + "columnName": "pricesIncludeTax", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "customerNote", + "columnName": "customerNote", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "discountTotal", + "columnName": "discountTotal", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "discountCodes", + "columnName": "discountCodes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "refundTotal", + "columnName": "refundTotal", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "customerId", + "columnName": "customerId", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "billingFirstName", + "columnName": "billingFirstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingLastName", + "columnName": "billingLastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCompany", + "columnName": "billingCompany", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingAddress1", + "columnName": "billingAddress1", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingAddress2", + "columnName": "billingAddress2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCity", + "columnName": "billingCity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingState", + "columnName": "billingState", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingPostcode", + "columnName": "billingPostcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCountry", + "columnName": "billingCountry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingEmail", + "columnName": "billingEmail", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingPhone", + "columnName": "billingPhone", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingFirstName", + "columnName": "shippingFirstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingLastName", + "columnName": "shippingLastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCompany", + "columnName": "shippingCompany", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingAddress1", + "columnName": "shippingAddress1", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingAddress2", + "columnName": "shippingAddress2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCity", + "columnName": "shippingCity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingState", + "columnName": "shippingState", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingPostcode", + "columnName": "shippingPostcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCountry", + "columnName": "shippingCountry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingPhone", + "columnName": "shippingPhone", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lineItems", + "columnName": "lineItems", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingLines", + "columnName": "shippingLines", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "feeLines", + "columnName": "feeLines", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxLines", + "columnName": "taxLines", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "couponLines", + "columnName": "couponLines", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "metaData", + "columnName": "metaData", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "paymentUrl", + "columnName": "paymentUrl", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "isEditable", + "columnName": "isEditable", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + }, + { + "fieldPath": "needsPayment", + "columnName": "needsPayment", + "affinity": "INTEGER" + }, + { + "fieldPath": "needsProcessing", + "columnName": "needsProcessing", + "affinity": "INTEGER" + }, + { + "fieldPath": "giftCardCode", + "columnName": "giftCardCode", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "giftCardAmount", + "columnName": "giftCardAmount", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "shippingTax", + "columnName": "shippingTax", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "createdVia", + "columnName": "createdVia", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "orderId" + ] + }, + "indices": [ + { + "name": "index_OrderEntity_localSiteId_orderId", + "unique": false, + "columnNames": [ + "localSiteId", + "orderId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_OrderEntity_localSiteId_orderId` ON `${TABLE_NAME}` (`localSiteId`, `orderId`)" + } + ] + }, + { + "tableName": "RefundEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `refundId` INTEGER NOT NULL, `data` TEXT NOT NULL, PRIMARY KEY(`siteId`, `orderId`, `refundId`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "refundId", + "columnName": "refundId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "data", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "orderId", + "refundId" + ] + } + }, + { + "tableName": "MetaData", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `parentItemId` INTEGER NOT NULL, `key` TEXT NOT NULL, `value` TEXT NOT NULL, `type` TEXT NOT NULL DEFAULT 'ORDER', PRIMARY KEY(`localSiteId`, `parentItemId`, `id`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "parentItemId", + "columnName": "parentItemId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'ORDER'" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "parentItemId", + "id" + ] + } + }, + { + "tableName": "InboxNotes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `remoteId` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `dateCreated` TEXT NOT NULL, `status` TEXT NOT NULL, `source` TEXT, `type` TEXT, `dateReminder` TEXT)", + "fields": [ + { + "fieldPath": "localId", + "columnName": "localId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "source", + "columnName": "source", + "affinity": "TEXT" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT" + }, + { + "fieldPath": "dateReminder", + "columnName": "dateReminder", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "localId" + ] + }, + "indices": [ + { + "name": "index_InboxNotes_remoteId_localSiteId", + "unique": true, + "columnNames": [ + "remoteId", + "localSiteId" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_InboxNotes_remoteId_localSiteId` ON `${TABLE_NAME}` (`remoteId`, `localSiteId`)" + } + ] + }, + { + "tableName": "InboxNoteActions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remoteId` INTEGER NOT NULL, `inboxNoteLocalId` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `label` TEXT NOT NULL, `url` TEXT NOT NULL, `query` TEXT, `status` TEXT, `primary` INTEGER NOT NULL, `actionedText` TEXT, PRIMARY KEY(`remoteId`, `inboxNoteLocalId`), FOREIGN KEY(`inboxNoteLocalId`) REFERENCES `InboxNotes`(`localId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "inboxNoteLocalId", + "columnName": "inboxNoteLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "query", + "columnName": "query", + "affinity": "TEXT" + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT" + }, + { + "fieldPath": "primary", + "columnName": "primary", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "actionedText", + "columnName": "actionedText", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "remoteId", + "inboxNoteLocalId" + ] + }, + "indices": [ + { + "name": "index_InboxNoteActions_inboxNoteLocalId", + "unique": false, + "columnNames": [ + "inboxNoteLocalId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_InboxNoteActions_inboxNoteLocalId` ON `${TABLE_NAME}` (`inboxNoteLocalId`)" + } + ], + "foreignKeys": [ + { + "table": "InboxNotes", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "inboxNoteLocalId" + ], + "referencedColumns": [ + "localId" + ] + } + ] + }, + { + "tableName": "TopPerformerProducts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `datePeriod` TEXT NOT NULL, `productId` INTEGER NOT NULL, `name` TEXT NOT NULL, `imageUrl` TEXT, `quantity` INTEGER NOT NULL, `currency` TEXT NOT NULL, `total` REAL NOT NULL, `millisSinceLastUpdated` INTEGER NOT NULL, PRIMARY KEY(`datePeriod`, `productId`, `localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "datePeriod", + "columnName": "datePeriod", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "productId", + "columnName": "productId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "imageUrl", + "columnName": "imageUrl", + "affinity": "TEXT" + }, + { + "fieldPath": "quantity", + "columnName": "quantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "total", + "columnName": "total", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "millisSinceLastUpdated", + "columnName": "millisSinceLastUpdated", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "datePeriod", + "productId", + "localSiteId" + ] + } + }, + { + "tableName": "TaxBasedOnSetting", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `selectedOption` TEXT NOT NULL, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "selectedOption", + "columnName": "selectedOption", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "TaxRate", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `country` TEXT, `state` TEXT, `postcode` TEXT, `city` TEXT, `rate` TEXT, `name` TEXT, `taxClass` TEXT, PRIMARY KEY(`id`, `localSiteId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "country", + "columnName": "country", + "affinity": "TEXT" + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT" + }, + { + "fieldPath": "postcode", + "columnName": "postcode", + "affinity": "TEXT" + }, + { + "fieldPath": "city", + "columnName": "city", + "affinity": "TEXT" + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT" + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT" + }, + { + "fieldPath": "taxClass", + "columnName": "taxClass", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "localSiteId" + ] + } + }, + { + "tableName": "WooPaymentsDepositsOverview", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `depositsEnabled` INTEGER, `depositsBlocked` INTEGER, `defaultCurrency` TEXT, `delayDays` INTEGER, `weeklyAnchor` TEXT, `monthlyAnchor` INTEGER, `interval` TEXT, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "account.depositsEnabled", + "columnName": "depositsEnabled", + "affinity": "INTEGER" + }, + { + "fieldPath": "account.depositsBlocked", + "columnName": "depositsBlocked", + "affinity": "INTEGER" + }, + { + "fieldPath": "account.defaultCurrency", + "columnName": "defaultCurrency", + "affinity": "TEXT" + }, + { + "fieldPath": "account.depositsSchedule.delayDays", + "columnName": "delayDays", + "affinity": "INTEGER" + }, + { + "fieldPath": "account.depositsSchedule.weeklyAnchor", + "columnName": "weeklyAnchor", + "affinity": "TEXT" + }, + { + "fieldPath": "account.depositsSchedule.monthlyAnchor", + "columnName": "monthlyAnchor", + "affinity": "INTEGER" + }, + { + "fieldPath": "account.depositsSchedule.interval", + "columnName": "interval", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "WooPaymentsDeposits", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `localSiteId` INTEGER NOT NULL, `depositId` TEXT, `date` INTEGER, `type` TEXT, `amount` INTEGER, `status` TEXT, `bankAccount` TEXT, `currency` TEXT, `automatic` INTEGER, `fee` INTEGER, `feePercentage` REAL, `created` INTEGER, `depositType` TEXT NOT NULL, FOREIGN KEY(`localSiteId`) REFERENCES `WooPaymentsDepositsOverview`(`localSiteId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "depositId", + "columnName": "depositId", + "affinity": "TEXT" + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT" + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "INTEGER" + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT" + }, + { + "fieldPath": "bankAccount", + "columnName": "bankAccount", + "affinity": "TEXT" + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT" + }, + { + "fieldPath": "automatic", + "columnName": "automatic", + "affinity": "INTEGER" + }, + { + "fieldPath": "fee", + "columnName": "fee", + "affinity": "INTEGER" + }, + { + "fieldPath": "feePercentage", + "columnName": "feePercentage", + "affinity": "REAL" + }, + { + "fieldPath": "created", + "columnName": "created", + "affinity": "INTEGER" + }, + { + "fieldPath": "depositType", + "columnName": "depositType", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "foreignKeys": [ + { + "table": "WooPaymentsDepositsOverview", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "localSiteId" + ], + "referencedColumns": [ + "localSiteId" + ] + } + ] + }, + { + "tableName": "WooPaymentsManualDeposits", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `localSiteId` INTEGER NOT NULL, `currency` TEXT, `date` INTEGER, FOREIGN KEY(`localSiteId`) REFERENCES `WooPaymentsDepositsOverview`(`localSiteId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT" + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "foreignKeys": [ + { + "table": "WooPaymentsDepositsOverview", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "localSiteId" + ], + "referencedColumns": [ + "localSiteId" + ] + } + ] + }, + { + "tableName": "WooPaymentsBalance", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `localSiteId` INTEGER NOT NULL, `amount` INTEGER, `currency` TEXT, `fee` INTEGER, `feePercentage` REAL, `net` INTEGER, `balanceType` TEXT NOT NULL, `card` INTEGER, FOREIGN KEY(`localSiteId`) REFERENCES `WooPaymentsDepositsOverview`(`localSiteId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "INTEGER" + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT" + }, + { + "fieldPath": "fee", + "columnName": "fee", + "affinity": "INTEGER" + }, + { + "fieldPath": "feePercentage", + "columnName": "feePercentage", + "affinity": "REAL" + }, + { + "fieldPath": "net", + "columnName": "net", + "affinity": "INTEGER" + }, + { + "fieldPath": "balanceType", + "columnName": "balanceType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sourceTypes.card", + "columnName": "card", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "foreignKeys": [ + { + "table": "WooPaymentsDepositsOverview", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "localSiteId" + ], + "referencedColumns": [ + "localSiteId" + ] + } + ] + }, + { + "tableName": "VisitorSummaryStatsEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `date` TEXT NOT NULL, `granularity` TEXT NOT NULL, `views` INTEGER NOT NULL, `visitors` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `date`, `granularity`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "granularity", + "columnName": "granularity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "views", + "columnName": "views", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "visitors", + "columnName": "visitors", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "date", + "granularity" + ] + } + }, + { + "tableName": "ShippingMethod", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `localSiteId` INTEGER NOT NULL, `title` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "id" + ] + } + }, + { + "tableName": "CustomerFromAnalytics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `userId` INTEGER NOT NULL, `avgOrderValue` REAL NOT NULL, `city` TEXT NOT NULL, `country` TEXT NOT NULL, `dateLastActive` TEXT NOT NULL, `dateLastActiveGmt` TEXT NOT NULL, `dateLastOrder` TEXT NOT NULL, `dateRegistered` TEXT NOT NULL, `dateRegisteredGmt` TEXT NOT NULL, `email` TEXT NOT NULL, `name` TEXT NOT NULL, `ordersCount` INTEGER NOT NULL, `postcode` TEXT NOT NULL, `state` TEXT NOT NULL, `totalSpend` REAL NOT NULL, `username` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `id`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "avgOrderValue", + "columnName": "avgOrderValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "city", + "columnName": "city", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "country", + "columnName": "country", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateLastActive", + "columnName": "dateLastActive", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateLastActiveGmt", + "columnName": "dateLastActiveGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateLastOrder", + "columnName": "dateLastOrder", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateRegistered", + "columnName": "dateRegistered", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateRegisteredGmt", + "columnName": "dateRegisteredGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ordersCount", + "columnName": "ordersCount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "postcode", + "columnName": "postcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "totalSpend", + "columnName": "totalSpend", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "id" + ] + } + }, + { + "tableName": "ProductEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `permalink` TEXT NOT NULL, `dateCreated` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `type` TEXT NOT NULL, `status` TEXT NOT NULL, `featured` INTEGER NOT NULL, `catalogVisibility` TEXT NOT NULL, `description` TEXT NOT NULL, `shortDescription` TEXT NOT NULL, `sku` TEXT NOT NULL, `globalUniqueId` TEXT NOT NULL, `price` TEXT NOT NULL, `regularPrice` TEXT NOT NULL, `salePrice` TEXT NOT NULL, `onSale` INTEGER NOT NULL, `totalSales` INTEGER NOT NULL, `purchasable` INTEGER NOT NULL, `dateOnSaleFrom` TEXT NOT NULL, `dateOnSaleTo` TEXT NOT NULL, `dateOnSaleFromGmt` TEXT NOT NULL, `dateOnSaleToGmt` TEXT NOT NULL, `virtual` INTEGER NOT NULL, `downloadable` INTEGER NOT NULL, `downloadLimit` INTEGER NOT NULL, `downloadExpiry` INTEGER NOT NULL, `soldIndividually` INTEGER NOT NULL, `externalUrl` TEXT NOT NULL, `buttonText` TEXT NOT NULL, `taxStatus` TEXT NOT NULL, `taxClass` TEXT NOT NULL, `manageStock` INTEGER NOT NULL, `stockQuantity` REAL NOT NULL, `stockStatus` TEXT NOT NULL, `backorders` TEXT NOT NULL, `backordersAllowed` INTEGER NOT NULL, `backordered` INTEGER NOT NULL, `shippingRequired` INTEGER NOT NULL, `shippingTaxable` INTEGER NOT NULL, `shippingClass` TEXT NOT NULL, `shippingClassId` INTEGER NOT NULL, `reviewsAllowed` INTEGER NOT NULL, `averageRating` TEXT NOT NULL, `ratingCount` INTEGER NOT NULL, `parentId` INTEGER NOT NULL, `purchaseNote` TEXT NOT NULL, `menuOrder` INTEGER NOT NULL, `categories` TEXT NOT NULL, `tags` TEXT NOT NULL, `images` TEXT NOT NULL, `attributes` TEXT NOT NULL, `variations` TEXT NOT NULL, `downloads` TEXT NOT NULL, `relatedIds` TEXT NOT NULL, `crossSellIds` TEXT NOT NULL, `upsellIds` TEXT NOT NULL, `groupedProductIds` TEXT NOT NULL, `weight` TEXT NOT NULL, `length` TEXT NOT NULL, `width` TEXT NOT NULL, `height` TEXT NOT NULL, `bundledItems` TEXT NOT NULL, `compositeComponents` TEXT NOT NULL, `specialStockStatus` TEXT NOT NULL, `bundleMinSize` REAL, `bundleMaxSize` REAL, `minAllowedQuantity` INTEGER NOT NULL, `maxAllowedQuantity` INTEGER NOT NULL, `groupOfQuantity` INTEGER NOT NULL, `combineVariationQuantities` INTEGER NOT NULL, `password` TEXT, `isSampleProduct` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `remoteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "permalink", + "columnName": "permalink", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "featured", + "columnName": "featured", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "catalogVisibility", + "columnName": "catalogVisibility", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shortDescription", + "columnName": "shortDescription", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sku", + "columnName": "sku", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "globalUniqueId", + "columnName": "globalUniqueId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "regularPrice", + "columnName": "regularPrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "salePrice", + "columnName": "salePrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "onSale", + "columnName": "onSale", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "totalSales", + "columnName": "totalSales", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "purchasable", + "columnName": "purchasable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateOnSaleFrom", + "columnName": "dateOnSaleFrom", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleTo", + "columnName": "dateOnSaleTo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleFromGmt", + "columnName": "dateOnSaleFromGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleToGmt", + "columnName": "dateOnSaleToGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "virtual", + "columnName": "virtual", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadable", + "columnName": "downloadable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadLimit", + "columnName": "downloadLimit", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadExpiry", + "columnName": "downloadExpiry", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "soldIndividually", + "columnName": "soldIndividually", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "externalUrl", + "columnName": "externalUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "buttonText", + "columnName": "buttonText", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxStatus", + "columnName": "taxStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxClass", + "columnName": "taxClass", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "manageStock", + "columnName": "manageStock", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "stockQuantity", + "columnName": "stockQuantity", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "stockStatus", + "columnName": "stockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backorders", + "columnName": "backorders", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backordersAllowed", + "columnName": "backordersAllowed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "backordered", + "columnName": "backordered", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shippingRequired", + "columnName": "shippingRequired", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shippingTaxable", + "columnName": "shippingTaxable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shippingClass", + "columnName": "shippingClass", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingClassId", + "columnName": "shippingClassId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "reviewsAllowed", + "columnName": "reviewsAllowed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "averageRating", + "columnName": "averageRating", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ratingCount", + "columnName": "ratingCount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "parentId", + "columnName": "parentId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "purchaseNote", + "columnName": "purchaseNote", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "menuOrder", + "columnName": "menuOrder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "categories", + "columnName": "categories", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "images", + "columnName": "images", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "attributes", + "columnName": "attributes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "variations", + "columnName": "variations", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloads", + "columnName": "downloads", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "relatedIds", + "columnName": "relatedIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "crossSellIds", + "columnName": "crossSellIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "upsellIds", + "columnName": "upsellIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "groupedProductIds", + "columnName": "groupedProductIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "length", + "columnName": "length", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "width", + "columnName": "width", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "height", + "columnName": "height", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "bundledItems", + "columnName": "bundledItems", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "compositeComponents", + "columnName": "compositeComponents", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "specialStockStatus", + "columnName": "specialStockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "bundleMinSize", + "columnName": "bundleMinSize", + "affinity": "REAL" + }, + { + "fieldPath": "bundleMaxSize", + "columnName": "bundleMaxSize", + "affinity": "REAL" + }, + { + "fieldPath": "minAllowedQuantity", + "columnName": "minAllowedQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "maxAllowedQuantity", + "columnName": "maxAllowedQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "groupOfQuantity", + "columnName": "groupOfQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "combineVariationQuantities", + "columnName": "combineVariationQuantities", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT" + }, + { + "fieldPath": "isSampleProduct", + "columnName": "isSampleProduct", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteId" + ] + } + }, + { + "tableName": "PosProductEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `sku` TEXT NOT NULL, `globalUniqueId` TEXT NOT NULL, `type` TEXT NOT NULL, `price` TEXT NOT NULL, `downloadable` INTEGER NOT NULL, `images` TEXT NOT NULL, `attributes` TEXT NOT NULL, `parentId` INTEGER, `status` TEXT NOT NULL, `regularPrice` TEXT NOT NULL, `salePrice` TEXT NOT NULL, `onSale` INTEGER NOT NULL, `description` TEXT NOT NULL, `shortDescription` TEXT NOT NULL, `manageStock` INTEGER NOT NULL, `stockQuantity` REAL, `stockStatus` TEXT NOT NULL, `backordersAllowed` INTEGER NOT NULL, `backordered` INTEGER NOT NULL, `categories` TEXT NOT NULL, `tags` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `variations` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `remoteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sku", + "columnName": "sku", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "globalUniqueId", + "columnName": "globalUniqueId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadable", + "columnName": "downloadable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "images", + "columnName": "images", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "attributes", + "columnName": "attributes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "parentId", + "columnName": "parentId", + "affinity": "INTEGER" + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "regularPrice", + "columnName": "regularPrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "salePrice", + "columnName": "salePrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "onSale", + "columnName": "onSale", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shortDescription", + "columnName": "shortDescription", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "manageStock", + "columnName": "manageStock", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "stockQuantity", + "columnName": "stockQuantity", + "affinity": "REAL" + }, + { + "fieldPath": "stockStatus", + "columnName": "stockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backordersAllowed", + "columnName": "backordersAllowed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "backordered", + "columnName": "backordered", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "categories", + "columnName": "categories", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "variations", + "columnName": "variations", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteId" + ] + } + }, + { + "tableName": "PosVariationEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteProductId` INTEGER NOT NULL, `remoteVariationId` INTEGER NOT NULL, `dateModified` TEXT NOT NULL, `sku` TEXT NOT NULL, `globalUniqueId` TEXT NOT NULL, `variationName` TEXT NOT NULL, `price` TEXT NOT NULL, `regularPrice` TEXT NOT NULL, `salePrice` TEXT NOT NULL, `description` TEXT NOT NULL, `stockQuantity` REAL NOT NULL, `stockStatus` TEXT NOT NULL, `manageStock` INTEGER NOT NULL, `backordered` INTEGER NOT NULL, `attributesJson` TEXT NOT NULL, `imageUrl` TEXT NOT NULL, `status` TEXT NOT NULL, `lastUpdated` TEXT NOT NULL, `downloadable` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `remoteProductId`, `remoteVariationId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteProductId", + "columnName": "remoteProductId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteVariationId", + "columnName": "remoteVariationId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sku", + "columnName": "sku", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "globalUniqueId", + "columnName": "globalUniqueId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "variationName", + "columnName": "variationName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "regularPrice", + "columnName": "regularPrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "salePrice", + "columnName": "salePrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "stockQuantity", + "columnName": "stockQuantity", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "stockStatus", + "columnName": "stockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "manageStock", + "columnName": "manageStock", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "backordered", + "columnName": "backordered", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "attributesJson", + "columnName": "attributesJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "imageUrl", + "columnName": "imageUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastUpdated", + "columnName": "lastUpdated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadable", + "columnName": "downloadable", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteProductId", + "remoteVariationId" + ] + } + }, + { + "tableName": "ProductCategoryEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteCategoryId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `parent` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `remoteCategoryId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteCategoryId", + "columnName": "remoteCategoryId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "parent", + "columnName": "parent", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteCategoryId" + ] + } + }, + { + "tableName": "ProductVariationEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteProductId` INTEGER NOT NULL, `remoteVariationId` INTEGER NOT NULL, `dateCreated` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `description` TEXT NOT NULL, `permalink` TEXT NOT NULL, `sku` TEXT NOT NULL, `globalUniqueId` TEXT NOT NULL, `status` TEXT NOT NULL, `price` TEXT NOT NULL, `regularPrice` TEXT NOT NULL, `salePrice` TEXT NOT NULL, `dateOnSaleFrom` TEXT NOT NULL, `dateOnSaleTo` TEXT NOT NULL, `dateOnSaleFromGmt` TEXT NOT NULL, `dateOnSaleToGmt` TEXT NOT NULL, `taxStatus` TEXT NOT NULL, `taxClass` TEXT NOT NULL, `onSale` INTEGER NOT NULL, `purchasable` INTEGER NOT NULL, `virtual` INTEGER NOT NULL, `downloadable` INTEGER NOT NULL, `downloadLimit` INTEGER NOT NULL, `downloadExpiry` INTEGER NOT NULL, `downloads` TEXT NOT NULL, `backorders` TEXT NOT NULL, `backordersAllowed` INTEGER NOT NULL, `backordered` INTEGER NOT NULL, `shippingClass` TEXT NOT NULL, `shippingClassId` INTEGER NOT NULL, `manageStock` INTEGER NOT NULL, `stockQuantity` REAL NOT NULL, `stockStatus` TEXT NOT NULL, `image` TEXT NOT NULL, `weight` TEXT NOT NULL, `length` TEXT NOT NULL, `width` TEXT NOT NULL, `height` TEXT NOT NULL, `minAllowedQuantity` INTEGER NOT NULL, `maxAllowedQuantity` INTEGER NOT NULL, `groupOfQuantity` INTEGER NOT NULL, `overrideProductQuantities` INTEGER NOT NULL, `menuOrder` INTEGER NOT NULL, `attributes` TEXT NOT NULL, `metadata` TEXT, PRIMARY KEY(`localSiteId`, `remoteProductId`, `remoteVariationId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteProductId", + "columnName": "remoteProductId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteVariationId", + "columnName": "remoteVariationId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "permalink", + "columnName": "permalink", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sku", + "columnName": "sku", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "globalUniqueId", + "columnName": "globalUniqueId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "regularPrice", + "columnName": "regularPrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "salePrice", + "columnName": "salePrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleFrom", + "columnName": "dateOnSaleFrom", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleTo", + "columnName": "dateOnSaleTo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleFromGmt", + "columnName": "dateOnSaleFromGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleToGmt", + "columnName": "dateOnSaleToGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxStatus", + "columnName": "taxStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxClass", + "columnName": "taxClass", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "onSale", + "columnName": "onSale", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "purchasable", + "columnName": "purchasable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "virtual", + "columnName": "virtual", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadable", + "columnName": "downloadable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadLimit", + "columnName": "downloadLimit", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadExpiry", + "columnName": "downloadExpiry", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloads", + "columnName": "downloads", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backorders", + "columnName": "backorders", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backordersAllowed", + "columnName": "backordersAllowed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "backordered", + "columnName": "backordered", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shippingClass", + "columnName": "shippingClass", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingClassId", + "columnName": "shippingClassId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "manageStock", + "columnName": "manageStock", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "stockQuantity", + "columnName": "stockQuantity", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "stockStatus", + "columnName": "stockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "image", + "columnName": "image", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "length", + "columnName": "length", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "width", + "columnName": "width", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "height", + "columnName": "height", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "minAllowedQuantity", + "columnName": "minAllowedQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "maxAllowedQuantity", + "columnName": "maxAllowedQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "groupOfQuantity", + "columnName": "groupOfQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "overrideProductQuantities", + "columnName": "overrideProductQuantities", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "menuOrder", + "columnName": "menuOrder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "attributes", + "columnName": "attributes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "metadata", + "columnName": "metadata", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteProductId", + "remoteVariationId" + ] + } + }, + { + "tableName": "ProductTagEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteTagId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `description` TEXT NOT NULL, `count` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `remoteTagId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteTagId", + "columnName": "remoteTagId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "count", + "columnName": "count", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteTagId" + ] + } + }, + { + "tableName": "ProductShippingClassEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteShippingClassId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `description` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `remoteShippingClassId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteShippingClassId", + "columnName": "remoteShippingClassId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteShippingClassId" + ] + } + }, + { + "tableName": "ProductReviewEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteProductReviewId` INTEGER NOT NULL, `remoteProductId` INTEGER NOT NULL, `dateCreated` TEXT NOT NULL, `status` TEXT NOT NULL, `reviewerName` TEXT NOT NULL, `reviewerEmail` TEXT NOT NULL, `review` TEXT NOT NULL, `rating` INTEGER NOT NULL, `verified` INTEGER NOT NULL, `reviewerAvatarsJson` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `remoteProductReviewId`, `remoteProductId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteProductReviewId", + "columnName": "remoteProductReviewId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteProductId", + "columnName": "remoteProductId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "reviewerName", + "columnName": "reviewerName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "reviewerEmail", + "columnName": "reviewerEmail", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "review", + "columnName": "review", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rating", + "columnName": "rating", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "verified", + "columnName": "verified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "reviewerAvatarsJson", + "columnName": "reviewerAvatarsJson", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteProductReviewId", + "remoteProductId" + ] + } + }, + { + "tableName": "ProductSettingsEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `weightUnit` TEXT NOT NULL, `dimensionUnit` TEXT NOT NULL, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "weightUnit", + "columnName": "weightUnit", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dimensionUnit", + "columnName": "dimensionUnit", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "CustomerEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `localSiteId` INTEGER NOT NULL, `remoteCustomerId` INTEGER NOT NULL, `avatarUrl` TEXT NOT NULL, `dateCreated` TEXT NOT NULL, `dateCreatedGmt` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `dateModifiedGmt` TEXT NOT NULL, `email` TEXT NOT NULL, `firstName` TEXT NOT NULL, `isPayingCustomer` INTEGER NOT NULL, `lastName` TEXT NOT NULL, `role` TEXT NOT NULL, `username` TEXT NOT NULL, `billingAddress1` TEXT NOT NULL, `billingAddress2` TEXT NOT NULL, `billingCity` TEXT NOT NULL, `billingCompany` TEXT NOT NULL, `billingCountry` TEXT NOT NULL, `billingEmail` TEXT NOT NULL, `billingFirstName` TEXT NOT NULL, `billingLastName` TEXT NOT NULL, `billingPhone` TEXT NOT NULL, `billingPostcode` TEXT NOT NULL, `billingState` TEXT NOT NULL, `shippingAddress1` TEXT NOT NULL, `shippingAddress2` TEXT NOT NULL, `shippingCity` TEXT NOT NULL, `shippingCompany` TEXT NOT NULL, `shippingCountry` TEXT NOT NULL, `shippingFirstName` TEXT NOT NULL, `shippingLastName` TEXT NOT NULL, `shippingPostcode` TEXT NOT NULL, `shippingState` TEXT NOT NULL, `analyticsCustomerId` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteCustomerId", + "columnName": "remoteCustomerId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "avatarUrl", + "columnName": "avatarUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreatedGmt", + "columnName": "dateCreatedGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModifiedGmt", + "columnName": "dateModifiedGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstName", + "columnName": "firstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isPayingCustomer", + "columnName": "isPayingCustomer", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastName", + "columnName": "lastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "role", + "columnName": "role", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingAddress1", + "columnName": "billingAddress1", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingAddress2", + "columnName": "billingAddress2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCity", + "columnName": "billingCity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCompany", + "columnName": "billingCompany", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCountry", + "columnName": "billingCountry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingEmail", + "columnName": "billingEmail", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingFirstName", + "columnName": "billingFirstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingLastName", + "columnName": "billingLastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingPhone", + "columnName": "billingPhone", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingPostcode", + "columnName": "billingPostcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingState", + "columnName": "billingState", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingAddress1", + "columnName": "shippingAddress1", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingAddress2", + "columnName": "shippingAddress2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCity", + "columnName": "shippingCity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCompany", + "columnName": "shippingCompany", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCountry", + "columnName": "shippingCountry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingFirstName", + "columnName": "shippingFirstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingLastName", + "columnName": "shippingLastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingPostcode", + "columnName": "shippingPostcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingState", + "columnName": "shippingState", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "analyticsCustomerId", + "columnName": "analyticsCustomerId", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "LocationEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`parentCode` TEXT NOT NULL, `code` TEXT NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`parentCode`, `code`))", + "fields": [ + { + "fieldPath": "parentCode", + "columnName": "parentCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "code", + "columnName": "code", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "parentCode", + "code" + ] + } + }, + { + "tableName": "OrderShipmentProviderEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `country` TEXT NOT NULL, `carrierName` TEXT NOT NULL, `carrierLink` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `carrierName`, `country`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "country", + "columnName": "country", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "carrierName", + "columnName": "carrierName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "carrierLink", + "columnName": "carrierLink", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "carrierName", + "country" + ] + } + }, + { + "tableName": "UserEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteUserId` INTEGER NOT NULL, `firstName` TEXT NOT NULL, `lastName` TEXT NOT NULL, `username` TEXT NOT NULL, `email` TEXT NOT NULL, `roles` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `remoteUserId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteUserId", + "columnName": "remoteUserId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "firstName", + "columnName": "firstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastName", + "columnName": "lastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roles", + "columnName": "roles", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteUserId" + ] + } + }, + { + "tableName": "TaxClassEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `slug`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "slug" + ] + } + }, + { + "tableName": "SettingsEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `currencyCode` TEXT NOT NULL, `currencyPosition` TEXT NOT NULL, `currencyThousandSeparator` TEXT NOT NULL, `currencyDecimalSeparator` TEXT NOT NULL, `currencyDecimalNumber` INTEGER NOT NULL, `countryCode` TEXT NOT NULL, `stateCode` TEXT NOT NULL, `address` TEXT NOT NULL, `address2` TEXT NOT NULL, `city` TEXT NOT NULL, `postalCode` TEXT NOT NULL, `couponsEnabled` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currencyPosition", + "columnName": "currencyPosition", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currencyThousandSeparator", + "columnName": "currencyThousandSeparator", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currencyDecimalSeparator", + "columnName": "currencyDecimalSeparator", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currencyDecimalNumber", + "columnName": "currencyDecimalNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "countryCode", + "columnName": "countryCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "stateCode", + "columnName": "stateCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address2", + "columnName": "address2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "city", + "columnName": "city", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "postalCode", + "columnName": "postalCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "couponsEnabled", + "columnName": "couponsEnabled", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "OrderSummaryEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `dateCreated` TEXT NOT NULL, PRIMARY KEY(`siteId`, `orderId`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "orderId" + ] + } + }, + { + "tableName": "OrderStatusEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `statusKey` TEXT NOT NULL, `label` TEXT NOT NULL, `statusCount` INTEGER NOT NULL, `position` INTEGER NOT NULL, PRIMARY KEY(`siteId`, `statusKey`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "statusKey", + "columnName": "statusKey", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "statusCount", + "columnName": "statusCount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "statusKey" + ] + } + }, + { + "tableName": "WooShippingLabelEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `labelId` INTEGER NOT NULL, `tracking` TEXT NOT NULL, `refundableAmount` TEXT NOT NULL, `status` TEXT NOT NULL, `created` TEXT, `carrierId` TEXT NOT NULL, `serviceName` TEXT NOT NULL, `commercialInvoiceUrl` TEXT, `isCommercialInvoiceSubmittedElectronically` INTEGER NOT NULL, `packageName` TEXT NOT NULL, `isLetter` INTEGER NOT NULL, `productNames` TEXT NOT NULL, `productIds` TEXT, `shipmentId` TEXT, `receiptItemId` INTEGER NOT NULL, `createdDate` TEXT, `mainReceiptId` INTEGER NOT NULL, `rate` TEXT NOT NULL, `currency` TEXT NOT NULL, `expiryDate` INTEGER NOT NULL, `usedDate` INTEGER, `refund` TEXT, `hazmatCategory` TEXT, `originAddress` TEXT, `destinationAddress` TEXT, PRIMARY KEY(`localSiteId`, `orderId`, `labelId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "labelId", + "columnName": "labelId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tracking", + "columnName": "tracking", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "refundableAmount", + "columnName": "refundableAmount", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "created", + "columnName": "created", + "affinity": "TEXT" + }, + { + "fieldPath": "carrierId", + "columnName": "carrierId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "serviceName", + "columnName": "serviceName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "commercialInvoiceUrl", + "columnName": "commercialInvoiceUrl", + "affinity": "TEXT" + }, + { + "fieldPath": "isCommercialInvoiceSubmittedElectronically", + "columnName": "isCommercialInvoiceSubmittedElectronically", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "packageName", + "columnName": "packageName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isLetter", + "columnName": "isLetter", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "productNames", + "columnName": "productNames", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "productIds", + "columnName": "productIds", + "affinity": "TEXT" + }, + { + "fieldPath": "shipmentId", + "columnName": "shipmentId", + "affinity": "TEXT" + }, + { + "fieldPath": "receiptItemId", + "columnName": "receiptItemId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdDate", + "columnName": "createdDate", + "affinity": "TEXT" + }, + { + "fieldPath": "mainReceiptId", + "columnName": "mainReceiptId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "expiryDate", + "columnName": "expiryDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usedDate", + "columnName": "usedDate", + "affinity": "INTEGER" + }, + { + "fieldPath": "refund", + "columnName": "refund", + "affinity": "TEXT" + }, + { + "fieldPath": "hazmatCategory", + "columnName": "hazmatCategory", + "affinity": "TEXT" + }, + { + "fieldPath": "originAddress", + "columnName": "originAddress", + "affinity": "TEXT" + }, + { + "fieldPath": "destinationAddress", + "columnName": "destinationAddress", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "orderId", + "labelId" + ] + } + }, + { + "tableName": "WooShippingShipmentEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `shipmentId` TEXT NOT NULL, `items` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `orderId`, `shipmentId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shipmentId", + "columnName": "shipmentId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "items", + "columnName": "items", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "orderId", + "shipmentId" + ] + } + }, + { + "tableName": "WooShippingPackagesEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `storeOptions` TEXT NOT NULL, `savedPackages` TEXT NOT NULL, `carrierPackageGroups` TEXT NOT NULL, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "storeOptions", + "columnName": "storeOptions", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "savedPackages", + "columnName": "savedPackages", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "carrierPackageGroups", + "columnName": "carrierPackageGroups", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "GlobalAttributeEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `remoteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `type` TEXT NOT NULL, `orderBy` TEXT NOT NULL, `hasArchives` INTEGER NOT NULL, PRIMARY KEY(`siteId`, `remoteId`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "orderBy", + "columnName": "orderBy", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasArchives", + "columnName": "hasArchives", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "remoteId" + ] + } + }, + { + "tableName": "GatewayEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `gatewayId` TEXT NOT NULL, `data` TEXT NOT NULL, PRIMARY KEY(`siteId`, `gatewayId`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "gatewayId", + "columnName": "gatewayId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "data", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "gatewayId" + ] + } + }, + { + "tableName": "NewVisitorStatsEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `granularity` TEXT NOT NULL, `date` TEXT NOT NULL, `startDate` TEXT NOT NULL, `endDate` TEXT NOT NULL, `quantity` TEXT NOT NULL, `fields` TEXT NOT NULL, `data` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `granularity`, `date`, `quantity`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "granularity", + "columnName": "granularity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "startDate", + "columnName": "startDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "endDate", + "columnName": "endDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "quantity", + "columnName": "quantity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fields", + "columnName": "fields", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "data", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "granularity", + "date", + "quantity" + ] + } + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '2d180f4d4c2ccaf6305a746959d1289d')" + ] + } +} \ No newline at end of file diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt index 088183d48d42..1e9bc9a42f77 100644 --- a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt @@ -120,6 +120,8 @@ interface WCDatabaseModule { @Provides internal fun providePosVariationsDao(database: WCAndroidDatabase) = database.posVariationsDao @Provides internal fun provideGatewaysDao(database: WCAndroidDatabase) = database.gatewaysDao + + @Provides internal fun provideNewVisitorStatsDao(database: WCAndroidDatabase) = database.newVisitorStatsDao } @Binds fun bindTransactionExecutor(database: WCAndroidDatabase): TransactionExecutor } diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/model/WCNewVisitorStatsModel.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/model/WCNewVisitorStatsModel.kt index b77cbe8f3aeb..250525f72ed5 100644 --- a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/model/WCNewVisitorStatsModel.kt +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/model/WCNewVisitorStatsModel.kt @@ -1,28 +1,25 @@ package org.wordpress.android.fluxc.model +import androidx.room.Entity import com.google.gson.Gson import com.google.gson.reflect.TypeToken -import com.yarolegovich.wellsql.core.Identifiable -import com.yarolegovich.wellsql.core.annotation.Column -import com.yarolegovich.wellsql.core.annotation.PrimaryKey -import com.yarolegovich.wellsql.core.annotation.Table -import org.wordpress.android.fluxc.persistence.WellSqlConfig +import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId import java.util.Locale -@Table(addOn = WellSqlConfig.ADDON_WOOCOMMERCE) -data class WCNewVisitorStatsModel(@PrimaryKey @Column private var id: Int = 0) : Identifiable { - @Column var localSiteId = 0 - @Column var granularity = "" // The granularity ("days", "weeks", "months", "years") - @Column var date = "" // The formatted end date of the data - @Column var startDate = "" // The start date of the data - @Column var endDate = "" // The end date of the data - @Column var quantity = "" // The quantity based on unit. i.e. 30 days, 17 weeks, 12 months, 2 years - @Column var isCustomField = false // to check if the data is for custom stats or default stats - @JvmName("setIsCustomField") - set - @Column var fields = "" // JSON - A map of numerical index to stat name, used to lookup the stat in the data object - @Column var data = "" // JSON - A list of lists; each nested list contains the data for a time period - +@Entity( + tableName = "NewVisitorStatsEntity", + primaryKeys = ["localSiteId", "granularity", "date", "quantity"], +) +data class WCNewVisitorStatsModel( + val localSiteId: LocalId, + val granularity: String, // The granularity ("days", "weeks", "months", "years") + val date: String, // The formatted end date of the data + val startDate: String, // The start date of the data + val endDate: String, // The end date of the data + val quantity: String, // The quantity based on unit. i.e. 30 days, 17 weeks, 12 months, 2 years + val fields: String, // JSON - A map of numerical index to stat name, used to lookup the stat in the data object + val data: String, // JSON - A list of lists; each nested list contains the data for a time period +) { // The fields JSON deserialized into a list of strings val fieldsList by lazy { val responseType = object : TypeToken>() {}.type @@ -46,11 +43,5 @@ data class WCNewVisitorStatsModel(@PrimaryKey @Column private var id: Int = 0) : private val gson by lazy { Gson() } } - override fun getId() = id - - override fun setId(id: Int) { - this.id = id - } - fun getIndexForField(field: VisitorStatsField) = fieldsList.indexOf(field.toString()) } diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/orderstats/OrderStatsRestClient.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/orderstats/OrderStatsRestClient.kt index 0a177cf271f1..53e7bb9cde51 100644 --- a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/orderstats/OrderStatsRestClient.kt +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/orderstats/OrderStatsRestClient.kt @@ -201,19 +201,16 @@ class OrderStatsRestClient @Inject constructor( return when (response) { is WPComGsonRequestBuilder.Response.Success -> { val statsData = response.data - val model = WCNewVisitorStatsModel().apply { - this.localSiteId = site.id - this.granularity = granularity.toString() - this.fields = statsData.fields.toString() - this.data = statsData.data.toString() - this.quantity = quantity.toString() - this.date = date - endDate?.let { this.endDate = it } - startDate?.let { - this.startDate = startDate - this.isCustomField = true - } - } + val model = WCNewVisitorStatsModel( + localSiteId = site.localId(), + granularity = granularity.toString(), + fields = statsData.fields.toString(), + data = statsData.data.toString(), + quantity = quantity.toString(), + date = date, + endDate = endDate ?: "", + startDate = startDate ?: "", + ) FetchNewVisitorStatsResponsePayload(site, granularity, model) } diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt index 9864273ca1dc..648d9ed24ae2 100644 --- a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt @@ -7,6 +7,7 @@ import androidx.room.Room import androidx.room.RoomDatabase import androidx.room.TypeConverters import androidx.room.withTransaction +import org.wordpress.android.fluxc.model.WCNewVisitorStatsModel import org.wordpress.android.fluxc.model.WCOrderShipmentProviderModel import org.wordpress.android.fluxc.model.WCOrderStatusModel import org.wordpress.android.fluxc.model.WCOrderSummaryModel @@ -39,6 +40,7 @@ import org.wordpress.android.fluxc.persistence.dao.GlobalAttributesDao import org.wordpress.android.fluxc.persistence.dao.InboxNotesDao import org.wordpress.android.fluxc.persistence.dao.LocationsDao import org.wordpress.android.fluxc.persistence.dao.MetaDataDao +import org.wordpress.android.fluxc.persistence.dao.NewVisitorStatsDao import org.wordpress.android.fluxc.persistence.dao.OrderNotesDao import org.wordpress.android.fluxc.persistence.dao.OrderShipmentProvidersDao import org.wordpress.android.fluxc.persistence.dao.OrderStatusDao @@ -118,7 +120,7 @@ import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_7_8 import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_8_9 import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_9_10 -const val WC_DATABASE_VERSION = 64 +const val WC_DATABASE_VERSION = 65 @Database( version = WC_DATABASE_VERSION, @@ -166,6 +168,7 @@ const val WC_DATABASE_VERSION = 64 WooShippingPackagesEntity::class, WCGlobalAttributeModel::class, GatewayEntity::class, + WCNewVisitorStatsModel::class, ], autoMigrations = [ AutoMigration(from = 12, to = 13), @@ -212,6 +215,7 @@ const val WC_DATABASE_VERSION = 64 AutoMigration(from = 60, to = 61), AutoMigration(from = 61, to = 62), AutoMigration(from = 63, to = 64), + AutoMigration(from = 64, to = 65), ] ) @TypeConverters( @@ -259,6 +263,7 @@ abstract class WCAndroidDatabase : RoomDatabase(), TransactionExecutor { abstract val wooShippingDao: WooShippingDao internal abstract val globalAttributesDao: GlobalAttributesDao internal abstract val gatewaysDao: GatewaysDao + internal abstract val newVisitorStatsDao: NewVisitorStatsDao companion object { fun buildDb( diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCVisitorStatsSqlUtils.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCVisitorStatsSqlUtils.kt deleted file mode 100644 index 92fed241144f..000000000000 --- a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCVisitorStatsSqlUtils.kt +++ /dev/null @@ -1,99 +0,0 @@ -package org.wordpress.android.fluxc.persistence - -import com.wellsql.generated.WCNewVisitorStatsModelTable -import com.yarolegovich.wellsql.WellSql -import org.wordpress.android.fluxc.model.SiteModel -import org.wordpress.android.fluxc.model.WCNewVisitorStatsModel -import org.wordpress.android.fluxc.store.WCStatsStore.StatsGranularity - -object WCVisitorStatsSqlUtils { - /** - * Methods to support the new v4 stats changes - */ - fun insertOrUpdateNewVisitorStats(stats: WCNewVisitorStatsModel): Int { - val statsResult = if (stats.isCustomField) { - WellSql.select(WCNewVisitorStatsModel::class.java) - .where().beginGroup() - .equals(WCNewVisitorStatsModelTable.LOCAL_SITE_ID, stats.localSiteId) - .equals(WCNewVisitorStatsModelTable.GRANULARITY, stats.granularity) - .equals(WCNewVisitorStatsModelTable.DATE, stats.date) - .equals(WCNewVisitorStatsModelTable.QUANTITY, stats.quantity) - .equals(WCNewVisitorStatsModelTable.IS_CUSTOM_FIELD, stats.isCustomField) - .endGroup().endWhere() - .asModel - } else { - WellSql.select(WCNewVisitorStatsModel::class.java) - .where().beginGroup() - .equals(WCNewVisitorStatsModelTable.LOCAL_SITE_ID, stats.localSiteId) - .equals(WCNewVisitorStatsModelTable.GRANULARITY, stats.granularity) - .equals(WCNewVisitorStatsModelTable.IS_CUSTOM_FIELD, stats.isCustomField) - .endGroup().endWhere() - .asModel - } - - if (statsResult.isEmpty()) { - /* - * if no visitor stats available for this particular date, quantity, granularity and site: - * - check if the incoming data is custom data or default data. - * - if custom data, we need to delete any previously cached custom data - * for the particular site before inserting incoming data - */ - if (stats.isCustomField) { - deleteNewCustomVisitorStatsForSite(stats.localSiteId) - } - - WellSql.insert(stats).asSingleTransaction(true).execute() - return 1 - } else { - // Update - val oldId = statsResult[0].id - return WellSql.update(WCNewVisitorStatsModel::class.java).whereId(oldId) - .put(stats, UpdateAllExceptId(WCNewVisitorStatsModel::class.java)).execute() - } - } - - fun getNewRawVisitorStatsForSiteGranularityQuantityAndDate( - site: SiteModel, - granularity: StatsGranularity, - quantity: String? = null, - date: String? = null, - isCustomField: Boolean = false - ): WCNewVisitorStatsModel? { - if (!isCustomField) - return getNewRawVisitorStatsForSiteAndGranularity(site, granularity) - - return WellSql.select(WCNewVisitorStatsModel::class.java) - .where() - .beginGroup() - .equals(WCNewVisitorStatsModelTable.LOCAL_SITE_ID, site.id) - .equals(WCNewVisitorStatsModelTable.GRANULARITY, granularity) - .equals(WCNewVisitorStatsModelTable.QUANTITY, quantity) - .equals(WCNewVisitorStatsModelTable.DATE, date) - .equals(WCNewVisitorStatsModelTable.IS_CUSTOM_FIELD, isCustomField) - .endGroup().endWhere() - .asModel.firstOrNull() - } - - private fun getNewRawVisitorStatsForSiteAndGranularity( - site: SiteModel, - granularity: StatsGranularity - ): WCNewVisitorStatsModel? { - return WellSql.select(WCNewVisitorStatsModel::class.java) - .where() - .beginGroup() - .equals(WCNewVisitorStatsModelTable.LOCAL_SITE_ID, site.id) - .equals(WCNewVisitorStatsModelTable.GRANULARITY, granularity) - .equals(WCNewVisitorStatsModelTable.IS_CUSTOM_FIELD, false) - .endGroup().endWhere() - .asModel.firstOrNull() - } - - private fun deleteNewCustomVisitorStatsForSite(siteId: Int): Int { - return WellSql.delete(WCNewVisitorStatsModel::class.java) - .where() - .equals(WCNewVisitorStatsModelTable.LOCAL_SITE_ID, siteId) - .equals(WCNewVisitorStatsModelTable.IS_CUSTOM_FIELD, true) - .endWhere() - .execute() - } -} diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/NewVisitorStatsDao.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/NewVisitorStatsDao.kt new file mode 100644 index 000000000000..371dc0a34e92 --- /dev/null +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/NewVisitorStatsDao.kt @@ -0,0 +1,46 @@ +package org.wordpress.android.fluxc.persistence.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Transaction +import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId +import org.wordpress.android.fluxc.model.WCNewVisitorStatsModel +import org.wordpress.android.fluxc.store.WCStatsStore.StatsGranularity + +@Dao +internal abstract class NewVisitorStatsDao { + @Query( + """ + SELECT * FROM NewVisitorStatsEntity + WHERE localSiteId = :siteId + AND granularity = :granularity + AND date = :date + AND quantity = :quantity + """ + ) + abstract suspend fun getStat( + siteId: LocalId, + granularity: StatsGranularity, + quantity: String?, + date: String?, + ): WCNewVisitorStatsModel? + + @Transaction + open suspend fun replaceStat(entity: WCNewVisitorStatsModel) { + deleteStatForSite(entity.localSiteId) + insertStat(entity) + } + + @Query( + """ + DELETE FROM NewVisitorStatsEntity + WHERE localSiteId = :siteId + """ + ) + protected abstract suspend fun deleteStatForSite(siteId: LocalId): Int + + @Insert(onConflict = OnConflictStrategy.REPLACE) + protected abstract suspend fun insertStat(entity: WCNewVisitorStatsModel) +} diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/store/WCStatsStore.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/store/WCStatsStore.kt index ec93962c1857..0f8d44f803e3 100644 --- a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/store/WCStatsStore.kt +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/store/WCStatsStore.kt @@ -6,16 +6,15 @@ import org.wordpress.android.fluxc.Dispatcher import org.wordpress.android.fluxc.Payload import org.wordpress.android.fluxc.action.WCStatsAction import org.wordpress.android.fluxc.annotations.action.Action -import org.wordpress.android.fluxc.logging.FluxCCrashLoggerProvider.crashLogger +import org.wordpress.android.fluxc.logging.FluxCCrashLoggerProvider import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.model.WCBundleStats import org.wordpress.android.fluxc.model.WCNewVisitorStatsModel import org.wordpress.android.fluxc.model.WCProductBundleItemReport import org.wordpress.android.fluxc.model.WCRevenueStatsModel import org.wordpress.android.fluxc.model.WCVisitorStatsSummary -import org.wordpress.android.fluxc.network.BaseRequest import org.wordpress.android.fluxc.network.BaseRequest.BaseNetworkError -import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType.UNKNOWN +import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooError import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooResult @@ -24,27 +23,25 @@ import org.wordpress.android.fluxc.network.rest.wpcom.wc.orderstats.OrderStatsRe import org.wordpress.android.fluxc.network.rest.wpcom.wc.orderstats.OrderStatsRestClient.OrderStatsApiUnit import org.wordpress.android.fluxc.network.rest.wpcom.wc.orderstats.VisitorStatsSummaryApiResponse import org.wordpress.android.fluxc.persistence.WCStatsSqlUtils -import org.wordpress.android.fluxc.persistence.WCVisitorStatsSqlUtils +import org.wordpress.android.fluxc.persistence.dao.NewVisitorStatsDao import org.wordpress.android.fluxc.persistence.dao.VisitorSummaryStatsDao import org.wordpress.android.fluxc.persistence.entity.VisitorSummaryStatsEntity import org.wordpress.android.fluxc.persistence.entity.toDomainModel -import org.wordpress.android.fluxc.store.WCStatsStore.OrderStatsErrorType.GENERIC_ERROR import org.wordpress.android.fluxc.tools.CoroutineEngine import org.wordpress.android.fluxc.utils.DateUtils import org.wordpress.android.util.AppLog -import org.wordpress.android.util.AppLog.T -import org.wordpress.android.util.AppLog.T.API import java.util.Locale import javax.inject.Inject import javax.inject.Singleton @Singleton -class WCStatsStore @Inject constructor( +class WCStatsStore @Inject internal constructor( dispatcher: Dispatcher, private val wcOrderStatsClient: OrderStatsRestClient, private val bundleStatsRestClient: BundleStatsRestClient, private val coroutineEngine: CoroutineEngine, - private val visitorSummaryStatsDao: VisitorSummaryStatsDao + private val visitorSummaryStatsDao: VisitorSummaryStatsDao, + private val newVisitorStatsDao: NewVisitorStatsDao, ) : Store(dispatcher) { companion object { private const val DATE_FORMAT_DAY = "yyyy-MM-dd" @@ -59,11 +56,11 @@ class WCStatsStore @Inject constructor( companion object { fun fromOrderStatsApiUnit(apiUnit: OrderStatsApiUnit): StatsGranularity { return when (apiUnit) { - OrderStatsApiUnit.HOUR -> StatsGranularity.HOURS - OrderStatsApiUnit.DAY -> StatsGranularity.DAYS - OrderStatsApiUnit.WEEK -> StatsGranularity.WEEKS - OrderStatsApiUnit.MONTH -> StatsGranularity.MONTHS - OrderStatsApiUnit.YEAR -> StatsGranularity.YEARS + OrderStatsApiUnit.HOUR -> HOURS + OrderStatsApiUnit.DAY -> DAYS + OrderStatsApiUnit.WEEK -> WEEKS + OrderStatsApiUnit.MONTH -> MONTHS + OrderStatsApiUnit.YEAR -> YEARS } } @@ -142,7 +139,10 @@ class WCStatsStore @Inject constructor( } } - class OrderStatsError(val type: OrderStatsErrorType = GENERIC_ERROR, val message: String = "") : OnChangedError + class OrderStatsError( + val type: OrderStatsErrorType = OrderStatsErrorType.GENERIC_ERROR, + val message: String = "" + ) : OnChangedError enum class OrderStatsErrorType { RESPONSE_NULL, @@ -151,23 +151,21 @@ class WCStatsStore @Inject constructor( GENERIC_ERROR; companion object { - private val reverseMap = OrderStatsErrorType.values().associateBy(OrderStatsErrorType::name) + private val reverseMap = entries.associateBy(OrderStatsErrorType::name) fun fromString(type: String) = reverseMap[type.uppercase(Locale.US)] ?: GENERIC_ERROR } } // OnChanged events class OnWCStatsChanged( - val rowsAffected: Int, val granularity: StatsGranularity, val quantity: String? = null, val date: String? = null, - val isCustomField: Boolean = false ) : OnChanged() { var causeOfChange: WCStatsAction? = null } - override fun onRegister() = AppLog.d(T.API, "WCStatsStore onRegister") + override fun onRegister() = AppLog.d(AppLog.T.API, "WCStatsStore onRegister") @Subscribe(threadMode = ThreadMode.ASYNC) override fun onAction(action: Action<*>) { @@ -176,7 +174,7 @@ class WCStatsStore @Inject constructor( WCStatsAction.FETCH_REVENUE_STATS_AVAILABILITY -> fetchRevenueStatsAvailability(action.payload as FetchRevenueStatsAvailabilityPayload) WCStatsAction.FETCHED_REVENUE_STATS_AVAILABILITY -> handleFetchRevenueStatsAvailabilityCompleted( - action.payload as FetchRevenueStatsAvailabilityResponsePayload + action.payload as FetchRevenueStatsAvailabilityResponsePayload ) WCStatsAction.FETCH_NEW_VISITOR_STATS -> Unit // Do nothing } @@ -186,16 +184,13 @@ class WCStatsStore @Inject constructor( * Returns the visitor data by date for the given [site] and [granularity]. * The returned map has the format: "2018-05-01" -> 15 */ - fun getNewVisitorStats( + suspend fun getNewVisitorStats( site: SiteModel, granularity: StatsGranularity, quantity: String? = null, - date: String? = null, - isCustomField: Boolean = false + date: String? = null ): Map { - val rawStats = WCVisitorStatsSqlUtils.getNewRawVisitorStatsForSiteGranularityQuantityAndDate( - site, granularity, quantity, date, isCustomField - ) + val rawStats = newVisitorStatsDao.getStat(site.localId(), granularity, quantity, date) rawStats?.let { visitorStatsModel -> val periodIndex = visitorStatsModel.getIndexForField(WCNewVisitorStatsModel.VisitorStatsField.PERIOD) val fieldIndex = visitorStatsModel.getIndexForField(WCNewVisitorStatsModel.VisitorStatsField.VISITORS) @@ -208,10 +203,11 @@ class WCStatsStore @Inject constructor( dataList = visitorStatsModel.dataList ) } - } ?: return mapOf() + } + return mapOf() } - fun getNewVisitorStats( + suspend fun getNewVisitorStats( granularity: StatsGranularity, startDate: String, endDate: String, @@ -219,8 +215,8 @@ class WCStatsStore @Inject constructor( ): Map { val quantity = getVisitorStatsQuantity(granularity, startDate, endDate) val date = DateUtils.getDateTimeForSite(site, DATE_FORMAT_DAY, endDate) - val rawStats = WCVisitorStatsSqlUtils.getNewRawVisitorStatsForSiteGranularityQuantityAndDate( - site, granularity, quantity.toString(), date, true + val rawStats = newVisitorStatsDao.getStat( + site.localId(), granularity, quantity.toString(), date ) rawStats?.let { visitorStatsModel -> val periodIndex = visitorStatsModel.getIndexForField(WCNewVisitorStatsModel.VisitorStatsField.PERIOD) @@ -234,7 +230,8 @@ class WCStatsStore @Inject constructor( dataList = visitorStatsModel.dataList ) } - } ?: return mapOf() + } + return mapOf() } private fun getVisitorsMap( @@ -251,7 +248,7 @@ class WCStatsStore @Inject constructor( val visits = if (visitsRawValue is Number) { visitsRawValue.toInt() } else { - crashLogger?.recordException( + FluxCCrashLoggerProvider.crashLogger?.recordException( exception = NumberFormatException("$visitsRawValue is not a valid number"), category = null ) @@ -268,7 +265,7 @@ class WCStatsStore @Inject constructor( endDate: String, interval: String, ): WooResult { - return coroutineEngine.withDefaultContext(T.API, this, "fetchProductBundlesStats") { + return coroutineEngine.withDefaultContext(AppLog.T.API, this, "fetchProductBundlesStats") { val response = bundleStatsRestClient.fetchBundleStats( site = site, startDate = startDate, @@ -289,7 +286,7 @@ class WCStatsStore @Inject constructor( WooResult(bundleStats) } - else -> WooResult(WooError(WooErrorType.GENERIC_ERROR, BaseRequest.GenericErrorType.UNKNOWN)) + else -> WooResult(WooError(WooErrorType.GENERIC_ERROR, GenericErrorType.UNKNOWN)) } } } @@ -300,7 +297,7 @@ class WCStatsStore @Inject constructor( endDate: String, quantity: Int ): WooResult> { - return coroutineEngine.withDefaultContext(T.API, this, "fetchProductBundlesReport") { + return coroutineEngine.withDefaultContext(AppLog.T.API, this, "fetchProductBundlesReport") { val response = bundleStatsRestClient.fetchBundleReport( site = site, startDate = startDate, @@ -325,7 +322,7 @@ class WCStatsStore @Inject constructor( WooResult(bundleStats) } - else -> WooResult(WooError(WooErrorType.GENERIC_ERROR, BaseRequest.GenericErrorType.UNKNOWN)) + else -> WooResult(WooError(WooErrorType.GENERIC_ERROR, GenericErrorType.UNKNOWN)) } } } @@ -337,29 +334,27 @@ class WCStatsStore @Inject constructor( val startDate = payload.startDate val endDate = payload.endDate val quantity = getVisitorStatsQuantity(payload.granularity, startDate, endDate) - return coroutineEngine.withDefaultContext(T.API, this, "fetchNewVisitorStats") { + return coroutineEngine.withDefaultContext(AppLog.T.API, this, "fetchNewVisitorStats") { val result = wcOrderStatsClient.fetchNewVisitorStats( - site = payload.site, - granularity = payload.granularity, - date = DateUtils.getDateTimeForSite(payload.site, DATE_FORMAT_DAY, endDate), - quantity = quantity, - force = payload.forced, - startDate = startDate, - endDate = endDate + site = payload.site, + granularity = payload.granularity, + date = DateUtils.getDateTimeForSite(payload.site, DATE_FORMAT_DAY, endDate), + quantity = quantity, + force = payload.forced, + startDate = startDate, + endDate = endDate ) return@withDefaultContext if (result.isError || result.stats == null) { - OnWCStatsChanged(0, payload.granularity).also { + OnWCStatsChanged(payload.granularity).also { it.error = result.error it.causeOfChange = WCStatsAction.FETCH_NEW_VISITOR_STATS } } else { - val rowsAffected = WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(result.stats) + newVisitorStatsDao.replaceStat(result.stats) OnWCStatsChanged( - rowsAffected, - payload.granularity, - result.stats.quantity, - result.stats.date, - result.stats.isCustomField + payload.granularity, + result.stats.quantity, + result.stats.date, ).also { it.causeOfChange = WCStatsAction.FETCH_NEW_VISITOR_STATS } @@ -408,7 +403,7 @@ class WCStatsStore @Inject constructor( val startDate = payload.startDate val endDate = payload.endDate - return coroutineEngine.withDefaultContext(API, this, "fetchRevenueStats") { + return coroutineEngine.withDefaultContext(AppLog.T.API, this, "fetchRevenueStats") { val result = wcOrderStatsClient.fetchRevenueStats( site = payload.site, granularity = payload.granularity, @@ -450,7 +445,7 @@ class WCStatsStore @Inject constructor( visitors = visitors ) - return coroutineEngine.withDefaultContext(T.API, this, "fetchVisitorStatsSummary") { + return coroutineEngine.withDefaultContext(AppLog.T.API, this, "fetchVisitorStatsSummary") { val response = wcOrderStatsClient.fetchVisitorStatsSummary( site = site, granularity = granularity, @@ -467,7 +462,7 @@ class WCStatsStore @Inject constructor( WooResult(entity.toDomainModel()) } - else -> WooResult(WooError(WooErrorType.GENERIC_ERROR, UNKNOWN)) + else -> WooResult(WooError(WooErrorType.GENERIC_ERROR, GenericErrorType.UNKNOWN)) } } } @@ -497,11 +492,11 @@ class WCStatsStore @Inject constructor( val onStatsChanged = with(payload) { if (isError) { return@with OnWCRevenueStatsChanged( - 0, granularity = StatsGranularity.YEARS, availability = payload.available + 0, granularity = StatsGranularity.YEARS, availability = payload.available ).also { it.error = payload.error } } else { return@with OnWCRevenueStatsChanged( - 0, granularity = StatsGranularity.YEARS, availability = payload.available + 0, granularity = StatsGranularity.YEARS, availability = payload.available ) } } @@ -516,9 +511,9 @@ class WCStatsStore @Inject constructor( endDate: String ): Map { val rawStats = getRawRevenueStats(site, granularity, startDate, endDate) - return rawStats?.getIntervalList()?.map { + return rawStats?.getIntervalList()?.associate { it.interval!! to it.subtotals?.totalSales!! - }?.toMap() ?: mapOf() + } ?: mapOf() } fun getOrderCountStats( @@ -528,9 +523,9 @@ class WCStatsStore @Inject constructor( endDate: String ): Map { val rawStats = getRawRevenueStats(site, granularity, startDate, endDate) - return rawStats?.getIntervalList()?.map { + return rawStats?.getIntervalList()?.associate { it.interval!! to it.subtotals?.ordersCount!! - }?.toMap() ?: mapOf() + } ?: mapOf() } fun getRawRevenueStats( @@ -540,7 +535,8 @@ class WCStatsStore @Inject constructor( endDate: String ): WCRevenueStatsModel? { return WCStatsSqlUtils.getRevenueStatsForSiteIntervalAndDate( - site, granularity, startDate, endDate) + site, granularity, startDate, endDate + ) } fun getRawRevenueStatsFromRangeId( diff --git a/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/persistence/dao/NewVisitorStatsDaoTest.kt b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/persistence/dao/NewVisitorStatsDaoTest.kt new file mode 100644 index 000000000000..c1ad2e785385 --- /dev/null +++ b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/persistence/dao/NewVisitorStatsDaoTest.kt @@ -0,0 +1,101 @@ +package org.wordpress.android.fluxc.persistence.dao + +import android.app.Application +import androidx.test.core.app.ApplicationProvider +import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId +import org.wordpress.android.fluxc.model.WCNewVisitorStatsModel +import org.wordpress.android.fluxc.persistence.DatabaseTestRule +import org.wordpress.android.fluxc.store.WCStatsStore.StatsGranularity + +@Config(manifest = Config.NONE) +@RunWith(RobolectricTestRunner::class) +class NewVisitorStatsDaoTest { + private lateinit var dao: NewVisitorStatsDao + + @Rule + @JvmField + val databaseRule = DatabaseTestRule(ApplicationProvider.getApplicationContext()) + + @Before + fun setUp() { + dao = databaseRule.db.newVisitorStatsDao + } + + @Test + fun `when replace stat, then get stat returns by quantity and date`() = runTest { + val stat = statDay1Site1 + dao.replaceStat(stat) + + val retrieved = dao.getStat( + stat.localSiteId, + StatsGranularity.DAYS, + stat.quantity, + stat.date + ) + + assertThat(retrieved).isEqualTo(stat) + } + + @Test + fun `when replace stat again for same site, then previous stat is deleted`() = runTest { + // Replace first stat + dao.replaceStat(statDay1Site1) + // Now replace a second stat for same site (should clear stat rows for that site) + dao.replaceStat(statDay2Site1) + + // First one should not be found anymore + val first = dao.getStat( + siteId1, + StatsGranularity.DAYS, + statDay1Site1.quantity, + statDay1Site1.date + ) + // Second one should be present + val second = dao.getStat( + siteId1, + StatsGranularity.DAYS, + statDay2Site1.quantity, + statDay2Site1.date + ) + + assertThat(first).isNull() + assertThat(second).isEqualTo(statDay2Site1) + } + + companion object { + private val siteId1 = LocalId(1) + + // Minimal valid payloads for fields and data (stringified JSON) + private const val FIELDS = "[\"period\",\"visitors\"]" + private const val DATA = "[[\"2019-08-01\",1]]" + + private val statDay1Site1 = WCNewVisitorStatsModel( + localSiteId = siteId1, + granularity = StatsGranularity.DAYS.toString(), + date = "2019-08-10", + startDate = "2019-08-10", + endDate = "2019-08-10", + quantity = "1", + fields = FIELDS, + data = DATA + ) + private val statDay2Site1 = WCNewVisitorStatsModel( + localSiteId = siteId1, + granularity = StatsGranularity.DAYS.toString(), + date = "2019-08-11", + startDate = "2019-08-11", + endDate = "2019-08-11", + quantity = "1", + fields = FIELDS, + data = DATA + ) + } +} diff --git a/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt similarity index 67% rename from libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt rename to libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt index 6d0aa24b04f4..8606ce5a114a 100644 --- a/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt +++ b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt @@ -1,10 +1,8 @@ -package org.wordpress.android.fluxc.wc.stats +package org.wordpress.android.fluxc.store import android.app.Application import androidx.test.core.app.ApplicationProvider import com.yarolegovich.wellsql.WellSql -import junit.framework.TestCase.assertFalse -import kotlinx.coroutines.runBlocking import org.hamcrest.CoreMatchers.anyOf import org.hamcrest.CoreMatchers.not import org.hamcrest.MatcherAssert.assertThat @@ -24,13 +22,11 @@ import org.wordpress.android.fluxc.Dispatcher import org.wordpress.android.fluxc.SingleStoreWellSqlConfigForTests import org.wordpress.android.fluxc.UnitTestUtils import org.wordpress.android.fluxc.model.SiteModel -import org.wordpress.android.fluxc.model.WCNewVisitorStatsModel import org.wordpress.android.fluxc.model.WCRevenueStatsModel import org.wordpress.android.fluxc.model.WCVisitorStatsSummary import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooError import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType -import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType.GENERIC_ERROR import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooPayload import org.wordpress.android.fluxc.network.rest.wpcom.wc.bundlestats.BundleStatsApiResponse import org.wordpress.android.fluxc.network.rest.wpcom.wc.bundlestats.BundleStatsRestClient @@ -38,27 +34,27 @@ import org.wordpress.android.fluxc.network.rest.wpcom.wc.bundlestats.BundleStats import org.wordpress.android.fluxc.network.rest.wpcom.wc.orderstats.OrderStatsRestClient import org.wordpress.android.fluxc.network.rest.wpcom.wc.orderstats.VisitorStatsSummaryApiResponse import org.wordpress.android.fluxc.persistence.DatabaseTestRule -import org.wordpress.android.fluxc.persistence.WCVisitorStatsSqlUtils import org.wordpress.android.fluxc.persistence.WellSqlConfig -import org.wordpress.android.fluxc.store.WCStatsStore import org.wordpress.android.fluxc.store.WCStatsStore.FetchRevenueStatsPayload import org.wordpress.android.fluxc.store.WCStatsStore.FetchRevenueStatsResponsePayload import org.wordpress.android.fluxc.store.WCStatsStore.StatsGranularity +import org.wordpress.android.fluxc.test import org.wordpress.android.fluxc.tools.initCoroutineEngine import org.wordpress.android.fluxc.utils.DateUtils import org.wordpress.android.fluxc.utils.SiteUtils.getCurrentDateTimeForSite +import org.wordpress.android.fluxc.wc.stats.WCStatsTestUtils import java.text.SimpleDateFormat import java.util.Date import java.util.Locale import kotlin.test.assertEquals +import kotlin.test.assertFalse import kotlin.test.assertTrue import org.hamcrest.CoreMatchers.`is` as isEqual -@Suppress("LargeClass") +@Suppress("LargeClass", "UnitTestNamingRule") @Config(manifest = Config.NONE) @RunWith(RobolectricTestRunner::class) class WCStatsStoreTest { - private val context = ApplicationProvider.getApplicationContext() @Rule @@ -72,12 +68,9 @@ class WCStatsStoreTest { @Before fun setUp() { val config = SingleStoreWellSqlConfigForTests( - context, - listOf( - WCRevenueStatsModel::class.java, - WCNewVisitorStatsModel::class.java - ), - WellSqlConfig.ADDON_WOOCOMMERCE + context, + listOf(WCRevenueStatsModel::class.java), + WellSqlConfig.Companion.ADDON_WOOCOMMERCE ) WellSql.init(config) config.reset() @@ -87,7 +80,8 @@ class WCStatsStoreTest { wcOrderStatsClient = mockOrderStatsRestClient, bundleStatsRestClient = mockBundleStatsRestClient, coroutineEngine = initCoroutineEngine(), - visitorSummaryStatsDao = databaseRule.db.visitorSummaryStatsDao + visitorSummaryStatsDao = databaseRule.db.visitorSummaryStatsDao, + newVisitorStatsDao = databaseRule.db.newVisitorStatsDao, ) } @@ -377,9 +371,20 @@ class WCStatsStoreTest { } @Test - fun testFetchCurrentDayRevenueStatsDate() = runBlocking { + @Suppress("LongMethod") + fun testFetchCurrentDayRevenueStatsDate() = test { val plus12SiteDate = SiteModel().apply { timezone = "12" }.let { - whenever(mockOrderStatsRestClient.fetchRevenueStats(any(), any(), any(), any(), any(), any(), any(), any()) + whenever( + mockOrderStatsRestClient.fetchRevenueStats( + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any() + ) ).thenReturn(FetchRevenueStatsResponsePayload(it, StatsGranularity.DAYS, WCRevenueStatsModel())) val startDate = DateUtils.getStartDateForSite(it, DateUtils.formatDate("yyyy-MM-dd'T'00:00:00", Date())) val endDate = DateUtils.getEndDateForSite(it) @@ -390,8 +395,16 @@ class WCStatsStoreTest { // The date value passed to the network client should match the current date on the site val dateArgument = argumentCaptor() - verify(mockOrderStatsRestClient).fetchRevenueStats(any(), any(), - dateArgument.capture(), any(), any(), any(), any(), any()) + verify(mockOrderStatsRestClient).fetchRevenueStats( + any(), + any(), + dateArgument.capture(), + any(), + any(), + any(), + any(), + any() + ) val siteDate = dateArgument.firstValue assertEquals(timeOnSite, siteDate) return@let siteDate @@ -400,7 +413,17 @@ class WCStatsStoreTest { reset(mockOrderStatsRestClient) val minus12SiteDate = SiteModel().apply { timezone = "-12" }.let { - whenever(mockOrderStatsRestClient.fetchRevenueStats(any(), any(), any(), any(), any(), any(), any(), any()) + whenever( + mockOrderStatsRestClient.fetchRevenueStats( + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any() + ) ).thenReturn(FetchRevenueStatsResponsePayload(it, StatsGranularity.DAYS, WCRevenueStatsModel())) val startDate = DateUtils.getStartDateForSite(it, DateUtils.formatDate("yyyy-MM-dd'T'00:00:00", Date())) val endDate = DateUtils.getEndDateForSite(it) @@ -411,8 +434,16 @@ class WCStatsStoreTest { // The date value passed to the network client should match the current date on the site val dateArgument = argumentCaptor() - verify(mockOrderStatsRestClient).fetchRevenueStats(any(), any(), dateArgument.capture(), any(), - any(), any(), any(), any()) + verify(mockOrderStatsRestClient).fetchRevenueStats( + any(), + any(), + dateArgument.capture(), + any(), + any(), + any(), + any(), + any() + ) val siteDate = dateArgument.firstValue assertEquals(timeOnSite, siteDate) return@let siteDate @@ -426,9 +457,20 @@ class WCStatsStoreTest { } @Test - fun testFetchCurrentDayRevenueStatsDateSpecificEndDate() = runBlocking { + @Suppress("LongMethod") + fun testFetchCurrentDayRevenueStatsDateSpecificEndDate() = test { val plus12SiteDate = SiteModel().apply { timezone = "12" }.let { - whenever(mockOrderStatsRestClient.fetchRevenueStats(any(), any(), any(), any(), any(), any(), any(), any()) + whenever( + mockOrderStatsRestClient.fetchRevenueStats( + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any() + ) ).thenReturn(FetchRevenueStatsResponsePayload(it, StatsGranularity.DAYS, WCRevenueStatsModel())) val startDate = DateUtils.getStartDateForSite(it, DateUtils.formatDate("yyyy-MM-dd'T'00:00:00", Date())) val endDate = DateUtils.formatDate("yyyy-MM-dd", Date()) @@ -440,8 +482,16 @@ class WCStatsStoreTest { // The date value passed to the network client should match the current date on the site val dateArgument = argumentCaptor() - verify(mockOrderStatsRestClient).fetchRevenueStats(any(), any(), - dateArgument.capture(), any(), any(), any(), any(), any()) + verify(mockOrderStatsRestClient).fetchRevenueStats( + any(), + any(), + dateArgument.capture(), + any(), + any(), + any(), + any(), + any() + ) val siteDate = dateArgument.firstValue assertEquals(timeOnSite, siteDate) return@let siteDate @@ -450,7 +500,17 @@ class WCStatsStoreTest { reset(mockOrderStatsRestClient) val minus12SiteDate = SiteModel().apply { timezone = "-12" }.let { - whenever(mockOrderStatsRestClient.fetchRevenueStats(any(), any(), any(), any(), any(), any(), any(), any()) + whenever( + mockOrderStatsRestClient.fetchRevenueStats( + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any() + ) ).thenReturn(FetchRevenueStatsResponsePayload(it, StatsGranularity.DAYS, WCRevenueStatsModel())) val startDate = DateUtils.getStartDateForSite(it, DateUtils.formatDate("yyyy-MM-dd'T'00:00:00", Date())) val endDate = DateUtils.getEndDateForSite(it) @@ -461,8 +521,16 @@ class WCStatsStoreTest { // The date value passed to the network client should match the current date on the site val dateArgument = argumentCaptor() - verify(mockOrderStatsRestClient).fetchRevenueStats(any(), any(), dateArgument.capture(), any(), - any(), any(), any(), any()) + verify(mockOrderStatsRestClient).fetchRevenueStats( + any(), + any(), + dateArgument.capture(), + any(), + any(), + any(), + any(), + any() + ) val siteDate = dateArgument.firstValue assertEquals(timeOnSite, siteDate) return@let siteDate @@ -477,7 +545,7 @@ class WCStatsStoreTest { @Test @Suppress("LongMethod") - fun testGetRevenueAndOrderStatsForSite() = runBlocking { + fun testGetRevenueAndOrderStatsForSite() = test { // revenue stats model for current day val currentDayStatsModel = WCStatsTestUtils.generateSampleRevenueStatsModel() val site = SiteModel().apply { id = currentDayStatsModel.localSiteId } @@ -486,31 +554,41 @@ class WCStatsStoreTest { Locale.getDefault() ) ) - whenever(mockOrderStatsRestClient.fetchRevenueStats(any(), any(), any(), any(), any(), any(), any(), any())) - .thenReturn( - FetchRevenueStatsResponsePayload( - site, - currentDayGranularity, - currentDayStatsModel - ) - ) + whenever( + mockOrderStatsRestClient.fetchRevenueStats( + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any() + ) + ).thenReturn( + FetchRevenueStatsResponsePayload( + site, + currentDayGranularity, + currentDayStatsModel + ) + ) wcStatsStore.fetchRevenueStats( - FetchRevenueStatsPayload( - site, - currentDayGranularity, - currentDayStatsModel.startDate, - currentDayStatsModel.endDate - ) + FetchRevenueStatsPayload( + site, + currentDayGranularity, + currentDayStatsModel.startDate, + currentDayStatsModel.endDate + ) ) // verify that the revenue stats & order count is not empty val currentDayRevenueStats = wcStatsStore.getGrossRevenueStats( - site, StatsGranularity.valueOf(currentDayStatsModel.interval.uppercase(Locale.getDefault())), - currentDayStatsModel.startDate, currentDayStatsModel.endDate + site, StatsGranularity.valueOf(currentDayStatsModel.interval.uppercase(Locale.getDefault())), + currentDayStatsModel.startDate, currentDayStatsModel.endDate ) val currentDayOrderStats = wcStatsStore.getOrderCountStats( - site, StatsGranularity.valueOf(currentDayStatsModel.interval.uppercase(Locale.getDefault())), - currentDayStatsModel.startDate, currentDayStatsModel.endDate + site, StatsGranularity.valueOf(currentDayStatsModel.interval.uppercase(Locale.getDefault())), + currentDayStatsModel.startDate, currentDayStatsModel.endDate ) assertTrue(currentDayRevenueStats.isNotEmpty()) @@ -518,36 +596,46 @@ class WCStatsStoreTest { // revenue stats model for this week val currentWeekStatsModel = - WCStatsTestUtils.generateSampleRevenueStatsModel( - interval = StatsGranularity.WEEKS.toString(), startDate = "2019-07-07", endDate = "2019-07-09" - ) - val curretnWeekGranularity = StatsGranularity.valueOf( + WCStatsTestUtils.generateSampleRevenueStatsModel( + interval = StatsGranularity.WEEKS.toString(), startDate = "2019-07-07", endDate = "2019-07-09" + ) + val currentWeekGranularity = StatsGranularity.valueOf( currentWeekStatsModel.interval.uppercase( Locale.getDefault() ) ) val currentWeekPayload = FetchRevenueStatsResponsePayload( - site, curretnWeekGranularity, currentWeekStatsModel + site, currentWeekGranularity, currentWeekStatsModel ) - whenever(mockOrderStatsRestClient.fetchRevenueStats(any(), any(), any(), any(), any(), any(), any(), any())) - .thenReturn(currentWeekPayload) + whenever( + mockOrderStatsRestClient.fetchRevenueStats( + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any() + ) + ).thenReturn(currentWeekPayload) wcStatsStore.fetchRevenueStats( - FetchRevenueStatsPayload( - site, - curretnWeekGranularity, - currentWeekStatsModel.startDate, - currentWeekStatsModel.endDate - ) + FetchRevenueStatsPayload( + site, + currentWeekGranularity, + currentWeekStatsModel.startDate, + currentWeekStatsModel.endDate + ) ) // verify that the revenue stats & order count is not empty val currentWeekRevenueStats = wcStatsStore.getGrossRevenueStats( - site, StatsGranularity.valueOf(currentWeekStatsModel.interval.uppercase(Locale.getDefault())), - currentWeekStatsModel.startDate, currentWeekStatsModel.endDate + site, StatsGranularity.valueOf(currentWeekStatsModel.interval.uppercase(Locale.getDefault())), + currentWeekStatsModel.startDate, currentWeekStatsModel.endDate ) val currentWeekOrderStats = wcStatsStore.getOrderCountStats( - site, StatsGranularity.valueOf(currentWeekStatsModel.interval.uppercase(Locale.getDefault())), - currentWeekStatsModel.startDate, currentWeekStatsModel.endDate + site, StatsGranularity.valueOf(currentWeekStatsModel.interval.uppercase(Locale.getDefault())), + currentWeekStatsModel.startDate, currentWeekStatsModel.endDate ) assertTrue(currentWeekRevenueStats.isNotEmpty()) @@ -555,36 +643,46 @@ class WCStatsStoreTest { // revenue stats model for this month val currentMonthStatsModel = - WCStatsTestUtils.generateSampleRevenueStatsModel( - interval = StatsGranularity.MONTHS.toString(), startDate = "2019-07-01", endDate = "2019-07-09" - ) + WCStatsTestUtils.generateSampleRevenueStatsModel( + interval = StatsGranularity.MONTHS.toString(), startDate = "2019-07-01", endDate = "2019-07-09" + ) val currentMonthGranularity = StatsGranularity.valueOf( currentMonthStatsModel.interval.uppercase( Locale.getDefault() ) ) val currentMonthPayload = FetchRevenueStatsResponsePayload( - site, currentMonthGranularity, currentMonthStatsModel + site, currentMonthGranularity, currentMonthStatsModel ) - whenever(mockOrderStatsRestClient.fetchRevenueStats(any(), any(), any(), any(), any(), any(), any(), any())) - .thenReturn(currentMonthPayload) + whenever( + mockOrderStatsRestClient.fetchRevenueStats( + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any() + ) + ).thenReturn(currentMonthPayload) wcStatsStore.fetchRevenueStats( - FetchRevenueStatsPayload( - site, - currentMonthGranularity, - currentMonthStatsModel.startDate, - currentMonthStatsModel.endDate - ) + FetchRevenueStatsPayload( + site, + currentMonthGranularity, + currentMonthStatsModel.startDate, + currentMonthStatsModel.endDate + ) ) // verify that the revenue stats & order count is not empty val currentMonthRevenueStats = wcStatsStore.getGrossRevenueStats( - site, StatsGranularity.valueOf(currentMonthStatsModel.interval.uppercase(Locale.getDefault())), - currentMonthStatsModel.startDate, currentMonthStatsModel.endDate + site, StatsGranularity.valueOf(currentMonthStatsModel.interval.uppercase(Locale.getDefault())), + currentMonthStatsModel.startDate, currentMonthStatsModel.endDate ) val currentMonthOrderStats = wcStatsStore.getOrderCountStats( - site, StatsGranularity.valueOf(currentMonthStatsModel.interval.uppercase(Locale.getDefault())), - currentMonthStatsModel.startDate, currentMonthStatsModel.endDate + site, StatsGranularity.valueOf(currentMonthStatsModel.interval.uppercase(Locale.getDefault())), + currentMonthStatsModel.startDate, currentMonthStatsModel.endDate ) assertTrue(currentMonthRevenueStats.isNotEmpty()) @@ -593,7 +691,7 @@ class WCStatsStoreTest { // current day stats for alternate site val site2 = SiteModel().apply { id = 8 } val altSiteOrderStatsModel = WCStatsTestUtils.generateSampleRevenueStatsModel( - localSiteId = site2.id, interval = StatsGranularity.DAYS.toString() + localSiteId = site2.id, interval = StatsGranularity.DAYS.toString() ) val allSiteCurrentDayGranularity = StatsGranularity.valueOf( altSiteOrderStatsModel.interval.uppercase( @@ -601,27 +699,37 @@ class WCStatsStoreTest { ) ) val allSiteCurrentDayPayload = FetchRevenueStatsResponsePayload( - site, allSiteCurrentDayGranularity, altSiteOrderStatsModel + site, allSiteCurrentDayGranularity, altSiteOrderStatsModel ) - whenever(mockOrderStatsRestClient.fetchRevenueStats(any(), any(), any(), any(), any(), any(), any(), any())) - .thenReturn(allSiteCurrentDayPayload) + whenever( + mockOrderStatsRestClient.fetchRevenueStats( + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any() + ) + ).thenReturn(allSiteCurrentDayPayload) wcStatsStore.fetchRevenueStats( - FetchRevenueStatsPayload( - site, - allSiteCurrentDayGranularity, - altSiteOrderStatsModel.startDate, - altSiteOrderStatsModel.endDate - ) + FetchRevenueStatsPayload( + site, + allSiteCurrentDayGranularity, + altSiteOrderStatsModel.startDate, + altSiteOrderStatsModel.endDate + ) ) // verify that the revenue stats & order count is not empty val altSiteCurrentDayRevenueStats = wcStatsStore.getGrossRevenueStats( - site, StatsGranularity.valueOf(altSiteOrderStatsModel.interval.uppercase(Locale.getDefault())), - altSiteOrderStatsModel.startDate, altSiteOrderStatsModel.endDate + site, StatsGranularity.valueOf(altSiteOrderStatsModel.interval.uppercase(Locale.getDefault())), + altSiteOrderStatsModel.startDate, altSiteOrderStatsModel.endDate ) val altSiteCurrentDayOrderStats = wcStatsStore.getOrderCountStats( - site, StatsGranularity.valueOf(altSiteOrderStatsModel.interval.uppercase(Locale.getDefault())), - altSiteOrderStatsModel.startDate, altSiteOrderStatsModel.endDate + site, StatsGranularity.valueOf(altSiteOrderStatsModel.interval.uppercase(Locale.getDefault())), + altSiteOrderStatsModel.startDate, altSiteOrderStatsModel.endDate ) assertTrue(altSiteCurrentDayRevenueStats.isNotEmpty()) @@ -631,54 +739,74 @@ class WCStatsStoreTest { val nonExistentSite = SiteModel().apply { id = 88 } val nonExistentSiteGranularity = StatsGranularity.valueOf(altSiteOrderStatsModel.interval) val nonExistentPayload = FetchRevenueStatsResponsePayload( - nonExistentSite, nonExistentSiteGranularity, altSiteOrderStatsModel + nonExistentSite, nonExistentSiteGranularity, altSiteOrderStatsModel ) - whenever(mockOrderStatsRestClient.fetchRevenueStats(any(), any(), any(), any(), any(), any(), any(), any())) - .thenReturn(nonExistentPayload) + whenever( + mockOrderStatsRestClient.fetchRevenueStats( + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any() + ) + ).thenReturn(nonExistentPayload) wcStatsStore.fetchRevenueStats( - FetchRevenueStatsPayload( - site, - nonExistentSiteGranularity, - altSiteOrderStatsModel.startDate, - altSiteOrderStatsModel.endDate - ) + FetchRevenueStatsPayload( + site, + nonExistentSiteGranularity, + altSiteOrderStatsModel.startDate, + altSiteOrderStatsModel.endDate + ) ) // verify that the revenue stats & order count is empty val nonExistentRevenueStats = wcStatsStore.getGrossRevenueStats( - nonExistentSite, StatsGranularity.valueOf( + nonExistentSite, StatsGranularity.valueOf( altSiteOrderStatsModel.interval.uppercase(Locale.getDefault()) ), - altSiteOrderStatsModel.startDate, altSiteOrderStatsModel.endDate + altSiteOrderStatsModel.startDate, altSiteOrderStatsModel.endDate ) val nonExistentOrderStats = wcStatsStore.getOrderCountStats( - nonExistentSite, StatsGranularity.valueOf( + nonExistentSite, StatsGranularity.valueOf( altSiteOrderStatsModel.interval.uppercase(Locale.getDefault()) ), - altSiteOrderStatsModel.startDate, altSiteOrderStatsModel.endDate + altSiteOrderStatsModel.startDate, altSiteOrderStatsModel.endDate ) assertTrue(nonExistentRevenueStats.isEmpty()) assertTrue(nonExistentOrderStats.isEmpty()) // missing data - whenever(mockOrderStatsRestClient.fetchRevenueStats(any(), any(), any(), any(), any(), any(), any(), any())) - .thenReturn(nonExistentPayload) + whenever( + mockOrderStatsRestClient.fetchRevenueStats( + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any() + ) + ).thenReturn(nonExistentPayload) wcStatsStore.fetchRevenueStats( - FetchRevenueStatsPayload( - site = site, - granularity = StatsGranularity.YEARS, - startDate = "2019-01-01", - endDate = "2019-01-07" - ) + FetchRevenueStatsPayload( + site = site, + granularity = StatsGranularity.YEARS, + startDate = "2019-01-01", + endDate = "2019-01-07" + ) ) // verify that the revenue stats & order count is empty val missingRevenueStats = wcStatsStore.getGrossRevenueStats( - site, StatsGranularity.YEARS, "2019-01-01", "2019-01-07" + site, StatsGranularity.YEARS, "2019-01-01", "2019-01-07" ) val missingOrderStats = wcStatsStore.getOrderCountStats( - site, StatsGranularity.YEARS, "2019-01-01", "2019-01-07" + site, StatsGranularity.YEARS, "2019-01-01", "2019-01-07" ) assertTrue(missingRevenueStats.isEmpty()) assertTrue(missingOrderStats.isEmpty()) @@ -686,35 +814,41 @@ class WCStatsStoreTest { @Test @Suppress("LongMethod") - fun testGetVisitorStatsForCurrentDayGranularity() { - // Test Scenario - 1: Generate default visitor stats i.e. isCustomField - false + fun testGetVisitorStatsForCurrentDayGranularity() = test { + // Test Scenario - 1: Generate default visitor stats // Get visitor Stats of the same site and granularity and assert not null val defaultDayVisitorStatsModel = WCStatsTestUtils.generateSampleNewVisitorStatsModel() - val site = SiteModel().apply { id = defaultDayVisitorStatsModel.localSiteId } - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(defaultDayVisitorStatsModel) + val site = SiteModel().apply { id = defaultDayVisitorStatsModel.localSiteId.value } + databaseRule.db.newVisitorStatsDao.replaceStat(defaultDayVisitorStatsModel) - val defaultDayVisitorStats = wcStatsStore.getNewVisitorStats(site, StatsGranularity.DAYS) + val defaultDayVisitorStats = wcStatsStore.getNewVisitorStats( + site, StatsGranularity.DAYS, defaultDayVisitorStatsModel.quantity, + defaultDayVisitorStatsModel.endDate + ) assertTrue(defaultDayVisitorStats.isNotEmpty()) // Test Scenario - 2: Generate default visitor stats with a different date // Get visitor of the same site and granularity and assert not null val defaultDayVisitorStatsModel2 = WCStatsTestUtils.generateSampleNewVisitorStatsModel( - endDate = "2019-08-02" + endDate = "2019-08-02" + ) + databaseRule.db.newVisitorStatsDao.replaceStat(defaultDayVisitorStatsModel2) + val defaultDayVisitorStats2 = wcStatsStore.getNewVisitorStats( + site, StatsGranularity.DAYS, defaultDayVisitorStatsModel2.quantity, + defaultDayVisitorStatsModel2.endDate ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(defaultDayVisitorStatsModel2) - val defaultDayVisitorStats2 = wcStatsStore.getNewVisitorStats(site, StatsGranularity.DAYS) assertTrue(defaultDayVisitorStats2.isNotEmpty()) - // Test Scenario - 3: Generate custom stats for same site i.e. isCustomField - true + // Test Scenario - 3: Generate stats for same site // Get visitor Stats of the same site and granularity and assert not null val customDayVisitorStatsModel = WCStatsTestUtils.generateSampleNewVisitorStatsModel( - quantity = "1", endDate = "2019-08-06", startDate = "2019-08-06" + quantity = "1", endDate = "2019-08-06", startDate = "2019-08-06" ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(customDayVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.replaceStat(customDayVisitorStatsModel) val customDayVisitorStats = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.DAYS, customDayVisitorStatsModel.quantity, - customDayVisitorStatsModel.endDate, customDayVisitorStatsModel.isCustomField + site, StatsGranularity.DAYS, customDayVisitorStatsModel.quantity, + customDayVisitorStatsModel.endDate ) assertTrue(customDayVisitorStats.isNotEmpty()) @@ -722,11 +856,11 @@ class WCStatsStoreTest { // for same site, same quantity, different date // Get visitor Stats of the same site and granularity and assert null val customDayVisitorStatsModel2 = WCStatsTestUtils.generateSampleNewVisitorStatsModel( - quantity = "1", endDate = "2019-01-01", startDate = "2019-01-01" + quantity = "1", endDate = "2019-01-01", startDate = "2019-01-01" ) val customDayVisitorStats2 = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.DAYS, customDayVisitorStatsModel2.quantity, - customDayVisitorStatsModel2.endDate, customDayVisitorStatsModel2.isCustomField + site, StatsGranularity.DAYS, customDayVisitorStatsModel2.quantity, + customDayVisitorStatsModel2.endDate ) assertTrue(customDayVisitorStats2.isEmpty()) @@ -734,53 +868,53 @@ class WCStatsStoreTest { // for same site, different quantity, different date // Get visitor Stats of the same site and granularity and assert null val customDayVisitorStatsModel3 = WCStatsTestUtils.generateSampleNewVisitorStatsModel( - quantity = "1", endDate = "2019-01-01", startDate = "2019-01-01" + quantity = "1", endDate = "2019-01-01", startDate = "2019-01-01" ) val customDayVisitorStats3 = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.DAYS, customDayVisitorStatsModel3.quantity, - customDayVisitorStatsModel3.endDate, customDayVisitorStatsModel3.isCustomField + site, StatsGranularity.DAYS, customDayVisitorStatsModel3.quantity, + customDayVisitorStatsModel3.endDate ) assertTrue(customDayVisitorStats3.isEmpty()) // Test Scenario - 6: Generate custom visitor stats for same site with different granularity (WEEKS), - // same date(2019-01-01), same quantity (1) i.e. isCustomField - true + // same date(2019-01-01), same quantity (1) // Get visitor Stats and assert Not Null // Now if another query ran for granularity - DAYS, with same date and same quantity: assert null val customWeekVisitorStatsModel = WCStatsTestUtils.generateSampleNewVisitorStatsModel( - quantity = "1", - endDate = "2019-02-01", startDate = "2019-02-01", - granularity = StatsGranularity.WEEKS.toString() + quantity = "1", + endDate = "2019-02-01", startDate = "2019-02-01", + granularity = StatsGranularity.WEEKS.toString() ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(customWeekVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.replaceStat(customWeekVisitorStatsModel) val customWeekVisitorStats = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, - customWeekVisitorStatsModel.endDate, customWeekVisitorStatsModel.isCustomField + site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, + customWeekVisitorStatsModel.endDate ) assertTrue(customWeekVisitorStats.isNotEmpty()) val customDayVisitorStats4 = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.DAYS, customDayVisitorStatsModel.quantity, - customDayVisitorStatsModel.endDate, customDayVisitorStatsModel.isCustomField + site, StatsGranularity.DAYS, customDayVisitorStatsModel.quantity, + customDayVisitorStatsModel.endDate ) assertTrue(customDayVisitorStats4.isEmpty()) - // Test Scenario - 7: Generate custom stats for different site(8) with same granularity(WEEKS), - // same date(2019-01-01), same quantity(1) i.e. isCustomField - true + // Test Scenario - 7: Generate stats for different site(8) with same granularity(WEEKS), + // same date(2019-01-01), same quantity(1) // Get visitor Stats and assert Not Null // Now if scenario 4 is run again it should assert NOT NULL, since the stats is for different sites val customWeekVisitorStatsModel2 = WCStatsTestUtils.generateSampleNewVisitorStatsModel( - localSiteId = 8, granularity = StatsGranularity.WEEKS.toString(), - quantity = "1", endDate = "2019-02-01", startDate = "2019-02-01" + localSiteId = 8, granularity = StatsGranularity.WEEKS.toString(), + quantity = "1", endDate = "2019-02-01", startDate = "2019-02-01" ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(customWeekVisitorStatsModel2) + databaseRule.db.newVisitorStatsDao.replaceStat(customWeekVisitorStatsModel2) val customWeekVisitorStats2 = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.WEEKS, customWeekVisitorStatsModel2.quantity, - customWeekVisitorStatsModel2.endDate, customWeekVisitorStatsModel2.isCustomField + site, StatsGranularity.WEEKS, customWeekVisitorStatsModel2.quantity, + customWeekVisitorStatsModel2.endDate ) assertTrue(customWeekVisitorStats2.isNotEmpty()) assertTrue(customWeekVisitorStats.isNotEmpty()) @@ -788,42 +922,51 @@ class WCStatsStoreTest { @Test @Suppress("LongMethod") - fun testGetVisitorStatsForThisWeekGranularity() { - // Test Scenario - 1: Generate default visitor stats i.e. isCustomField - false + fun testGetVisitorStatsForThisWeekGranularity() = test { + // Test Scenario - 1: Generate default visitor stats // Get visitor Stats of the same site and granularity and assert not null val defaultWeekVisitorStatsModel = WCStatsTestUtils.generateSampleNewVisitorStatsModel( - granularity = StatsGranularity.WEEKS.toString() + granularity = StatsGranularity.WEEKS.toString() ) - val site = SiteModel().apply { id = defaultWeekVisitorStatsModel.localSiteId } - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(defaultWeekVisitorStatsModel) + val site = SiteModel().apply { id = defaultWeekVisitorStatsModel.localSiteId.value } + databaseRule.db.newVisitorStatsDao.replaceStat(defaultWeekVisitorStatsModel) - val defaultWeekVisitorStats = wcStatsStore.getNewVisitorStats(site, StatsGranularity.WEEKS) + val defaultWeekVisitorStats = wcStatsStore.getNewVisitorStats( + site, StatsGranularity.WEEKS, defaultWeekVisitorStatsModel.quantity, + defaultWeekVisitorStatsModel.endDate + ) assertTrue(defaultWeekVisitorStats.isNotEmpty()) // query for days granularity. the visitor stats should be empty - val defaultDayVisitorStats = wcStatsStore.getNewVisitorStats(site, StatsGranularity.DAYS) + val defaultDayVisitorStats = wcStatsStore.getNewVisitorStats( + site, StatsGranularity.DAYS, defaultWeekVisitorStatsModel.quantity, + defaultWeekVisitorStatsModel.endDate + ) assertTrue(defaultDayVisitorStats.isEmpty()) // Test Scenario - 2: Generate default visitor stats with a different date // Get visitor of the same site and granularity and assert not null val defaultWeekVisitorStatsModel2 = WCStatsTestUtils.generateSampleNewVisitorStatsModel( - granularity = StatsGranularity.WEEKS.toString(), endDate = "2019-03-20" + granularity = StatsGranularity.WEEKS.toString(), endDate = "2019-03-20" + ) + databaseRule.db.newVisitorStatsDao.replaceStat(defaultWeekVisitorStatsModel2) + val defaultWeekVisitorStats2 = wcStatsStore.getNewVisitorStats( + site, StatsGranularity.WEEKS, defaultWeekVisitorStatsModel2.quantity, + defaultWeekVisitorStatsModel2.endDate ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(defaultWeekVisitorStatsModel2) - val defaultWeekVisitorStats2 = wcStatsStore.getNewVisitorStats(site, StatsGranularity.WEEKS) assertTrue(defaultWeekVisitorStats2.isNotEmpty()) - // Test Scenario - 3: Generate custom stats for same site i.e. isCustomField - true + // Test Scenario - 3: Generate stats for same site // Get visitor Stats of the same site and granularity and assert not null val customWeekVisitorStatsModel = WCStatsTestUtils.generateSampleNewVisitorStatsModel( - granularity = StatsGranularity.WEEKS.toString(), quantity = "1", - endDate = "2019-08-01", startDate = "2019-08-01" + granularity = StatsGranularity.WEEKS.toString(), quantity = "1", + endDate = "2019-08-01", startDate = "2019-08-01" ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(customWeekVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.replaceStat(customWeekVisitorStatsModel) val customWeekVisitorStats = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, - customWeekVisitorStatsModel.endDate, customWeekVisitorStatsModel.isCustomField + site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, + customWeekVisitorStatsModel.endDate ) assertTrue(customWeekVisitorStats.isNotEmpty()) @@ -831,12 +974,12 @@ class WCStatsStoreTest { // for same site, same quantity, different date // Get visitor Stats of the same site and granularity and assert null val customWeekVisitorStatsModel2 = WCStatsTestUtils.generateSampleNewVisitorStatsModel( - granularity = StatsGranularity.WEEKS.toString(), quantity = "1", - endDate = "2019-07-01", startDate = "2019-07-01" + granularity = StatsGranularity.WEEKS.toString(), quantity = "1", + endDate = "2019-07-01", startDate = "2019-07-01" ) val customWeekVisitorStats2 = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.WEEKS, customWeekVisitorStatsModel2.quantity, - customWeekVisitorStatsModel2.endDate, customWeekVisitorStatsModel2.isCustomField + site, StatsGranularity.WEEKS, customWeekVisitorStatsModel2.quantity, + customWeekVisitorStatsModel2.endDate ) assertTrue(customWeekVisitorStats2.isEmpty()) @@ -844,59 +987,60 @@ class WCStatsStoreTest { // for same site, different quantity, different date // Get visitor Stats of the same site and granularity and assert null val customWeekVisitorStatsModel3 = WCStatsTestUtils.generateSampleNewVisitorStatsModel( - granularity = StatsGranularity.WEEKS.toString(), quantity = "1", - endDate = "2019-07-01", startDate = "2019-07-01" + granularity = StatsGranularity.WEEKS.toString(), quantity = "1", + endDate = "2019-07-01", startDate = "2019-07-01" ) val customWeekVisitorStats3 = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.WEEKS, customWeekVisitorStatsModel3.quantity, - customWeekVisitorStatsModel3.endDate, customWeekVisitorStatsModel3.isCustomField + site, StatsGranularity.WEEKS, customWeekVisitorStatsModel3.quantity, + customWeekVisitorStatsModel3.endDate ) assertTrue(customWeekVisitorStats3.isEmpty()) // Test Scenario - 6: Generate custom visitor stats for same site with different granularity (MONTHS), - // same date(2019-01-01), same quantity (1) i.e. isCustomField - true + // same date(2019-01-01), same quantity (1) // Get visitor Stats and assert Not Null // Now if another query ran for granularity - WEEKS, with same date and same quantity: assert null val customMonthVisitorStatsModel = WCStatsTestUtils.generateSampleNewVisitorStatsModel( - quantity = "1", endDate = "2019-08-01", startDate = "2019-08-01", - granularity = StatsGranularity.MONTHS.toString()) + quantity = "1", endDate = "2019-08-01", startDate = "2019-08-01", + granularity = StatsGranularity.MONTHS.toString() + ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(customMonthVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.replaceStat(customMonthVisitorStatsModel) val customMonthVisitorStats = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.MONTHS, customMonthVisitorStatsModel.quantity, - customMonthVisitorStatsModel.endDate, customMonthVisitorStatsModel.isCustomField + site, StatsGranularity.MONTHS, customMonthVisitorStatsModel.quantity, + customMonthVisitorStatsModel.endDate ) assertTrue(customMonthVisitorStats.isNotEmpty()) val customWeekVisitorStats4 = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, - customWeekVisitorStatsModel.endDate, customWeekVisitorStatsModel.isCustomField + site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, + customWeekVisitorStatsModel.endDate ) assertTrue(customWeekVisitorStats4.isEmpty()) - // Test Scenario - 7: Generate custom stats for different site(8) with same granularity(MONTHS), - // same date(2019-01-01), same quantity(1) i.e. isCustomField - true + // Test Scenario - 7: Generate stats for different site(8) with same granularity(MONTHS), + // same date(2019-01-01), same quantity(1) // Get visitor Stats and assert Not Null // Now if scenario 4 is run again it should assert NOT NULL, since the stats is for different sites val customMonthVisitorStatsModel2 = WCStatsTestUtils.generateSampleNewVisitorStatsModel( - localSiteId = 8, granularity = StatsGranularity.MONTHS.toString(), - quantity = "1", endDate = "2019-08-01", startDate = "2019-08-01" + localSiteId = 8, granularity = StatsGranularity.MONTHS.toString(), + quantity = "1", endDate = "2019-08-01", startDate = "2019-08-01" ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(customMonthVisitorStatsModel2) + databaseRule.db.newVisitorStatsDao.replaceStat(customMonthVisitorStatsModel2) val customMonthVisitorStats2 = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.MONTHS, customMonthVisitorStatsModel2.quantity, - customMonthVisitorStatsModel2.endDate, customMonthVisitorStatsModel2.isCustomField + site, StatsGranularity.MONTHS, customMonthVisitorStatsModel2.quantity, + customMonthVisitorStatsModel2.endDate ) assertTrue(customMonthVisitorStats2.isNotEmpty()) assertTrue(customMonthVisitorStats.isNotEmpty()) } @Test - fun testGetNewVisitorStatsWithInvalidData() { + fun testGetNewVisitorStatsWithInvalidData() = test { // wrong-visitor-stats-data.json includes different wrong formatted data to ensure // that getNewVisitorStats is resilient and can recover from unexpected data // @@ -904,20 +1048,23 @@ class WCStatsStoreTest { granularity = StatsGranularity.WEEKS.toString(), data = UnitTestUtils.getStringFromResourceFile(this.javaClass, "wc/wrong-visitor-stats-data.json") ) - val site = SiteModel().apply { id = defaultWeekVisitorStatsModel.localSiteId } - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(defaultWeekVisitorStatsModel) + val site = SiteModel().apply { id = defaultWeekVisitorStatsModel.localSiteId.value } + databaseRule.db.newVisitorStatsDao.replaceStat(defaultWeekVisitorStatsModel) - val defaultWeekVisitorStats = wcStatsStore.getNewVisitorStats(site, StatsGranularity.WEEKS) + val defaultWeekVisitorStats = wcStatsStore.getNewVisitorStats( + site, StatsGranularity.WEEKS, defaultWeekVisitorStatsModel.quantity, + defaultWeekVisitorStatsModel.endDate + ) assertTrue(defaultWeekVisitorStats.isNotEmpty()) - assertEquals(defaultWeekVisitorStats["2019-06-23"],10) - assertEquals(defaultWeekVisitorStats["2019-06-22"],20) - assertEquals(defaultWeekVisitorStats["2019-07-16"],0) - assertEquals(defaultWeekVisitorStats["2019-07-17"],0) - assertEquals(defaultWeekVisitorStats["2019-07-18"],0) + assertEquals(defaultWeekVisitorStats["2019-06-23"], 10) + assertEquals(defaultWeekVisitorStats["2019-06-22"], 20) + assertEquals(defaultWeekVisitorStats["2019-07-16"], 0) + assertEquals(defaultWeekVisitorStats["2019-07-17"], 0) + assertEquals(defaultWeekVisitorStats["2019-07-18"], 0) } @Test - fun testFetchBundlesErrorResponse() = runBlocking { + fun testFetchBundlesErrorResponse() = test { val error = WooError( type = WooErrorType.INVALID_RESPONSE, original = GenericErrorType.INVALID_RESPONSE, @@ -941,7 +1088,7 @@ class WCStatsStoreTest { } @Test - fun testFetchBundlesNullResponse() = runBlocking { + fun testFetchBundlesNullResponse() = test { val response: WooPayload = WooPayload(null) whenever(mockBundleStatsRestClient.fetchBundleStats(any(), any(), any(), any())) @@ -960,7 +1107,7 @@ class WCStatsStoreTest { } @Test - fun testFetchBundlesSuccessResponse() = runBlocking { + fun testFetchBundlesSuccessResponse() = test { val totals = BundleStatsTotals( itemsSold = 5, netRevenue = 1000.00 @@ -980,12 +1127,12 @@ class WCStatsStoreTest { assertFalse(result.isError) assertTrue(result.model != null) - assertEquals(result.model!!.itemsSold, totals.itemsSold) - assertEquals(result.model!!.netRevenue, totals.netRevenue) + assertEquals(result.model.itemsSold, totals.itemsSold) + assertEquals(result.model.netRevenue, totals.netRevenue) } @Test - fun testSuccessfulFetchingVisitorSummaryStats() = runBlocking { + fun testSuccessfulFetchingVisitorSummaryStats() = test { val site = SiteModel().apply { id = 0 } val apiResponse = VisitorStatsSummaryApiResponse( date = "2024-03-01", @@ -1017,7 +1164,7 @@ class WCStatsStoreTest { } @Test - fun testFailedFetchingVisitorSummaryStats() = runBlocking { + fun testFailedFetchingVisitorSummaryStats() = test { val site = SiteModel().apply { id = 0 } whenever( mockOrderStatsRestClient.fetchVisitorStatsSummary( @@ -1026,7 +1173,7 @@ class WCStatsStoreTest { date = "2024-03-01", force = false ) - ).thenReturn(WooPayload(WooError(GENERIC_ERROR, GenericErrorType.UNKNOWN))) + ).thenReturn(WooPayload(WooError(WooErrorType.GENERIC_ERROR, GenericErrorType.UNKNOWN))) val result = wcStatsStore.fetchVisitorStatsSummary( site = site, diff --git a/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsTestUtils.kt b/libs/fluxc-plugin/src/testFixtures/kotlin/org/wordpress/android/fluxc/wc/stats/WCStatsTestUtils.kt similarity index 80% rename from libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsTestUtils.kt rename to libs/fluxc-plugin/src/testFixtures/kotlin/org/wordpress/android/fluxc/wc/stats/WCStatsTestUtils.kt index f3710fa3079d..e72dde309e88 100644 --- a/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsTestUtils.kt +++ b/libs/fluxc-plugin/src/testFixtures/kotlin/org/wordpress/android/fluxc/wc/stats/WCStatsTestUtils.kt @@ -1,6 +1,7 @@ package org.wordpress.android.fluxc.wc.stats import org.wordpress.android.fluxc.UnitTestUtils +import org.wordpress.android.fluxc.model.LocalOrRemoteId import org.wordpress.android.fluxc.model.WCNewVisitorStatsModel import org.wordpress.android.fluxc.model.WCRevenueStatsModel import org.wordpress.android.fluxc.store.WCStatsStore.StatsGranularity @@ -16,6 +17,7 @@ object WCStatsTestUtils { /** * Generates a sample [WCRevenueStatsModel] */ + @Suppress("MagicNumber") fun generateSampleRevenueStatsModel( localSiteId: Int = 6, interval: String = StatsGranularity.DAYS.toString(), @@ -35,6 +37,7 @@ object WCStatsTestUtils { /** * Generates a sample [WCNewVisitorStatsModel] */ + @Suppress("LongParameterList") fun generateSampleNewVisitorStatsModel( localSiteId: Int = 6, granularity: String = StatsGranularity.DAYS.toString(), @@ -44,18 +47,15 @@ object WCStatsTestUtils { fields: String = UnitTestUtils.getStringFromResourceFile(this.javaClass, "wc/visitor-stats-fields.json"), data: String = UnitTestUtils.getStringFromResourceFile(this.javaClass, "wc/visitor-stats-data.json") ): WCNewVisitorStatsModel { - return WCNewVisitorStatsModel().apply { - this.localSiteId = localSiteId - this.granularity = granularity - this.quantity = quantity - this.endDate = endDate - this.fields = fields - this.data = data - this.date = endDate - startDate?.let { - this.startDate = it - this.isCustomField = true - } - } + return WCNewVisitorStatsModel( + localSiteId = LocalOrRemoteId.LocalId(localSiteId), + granularity = granularity, + quantity = quantity, + endDate = endDate, + fields = fields, + data = data, + date = endDate, + startDate = startDate ?: "", + ) } } diff --git a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/WellSqlConfig.kt b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/WellSqlConfig.kt index 39a4020eda9f..ab94a6f8c0a6 100644 --- a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/WellSqlConfig.kt +++ b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/WellSqlConfig.kt @@ -40,7 +40,7 @@ open class WellSqlConfig : DefaultWellConfig { annotation class AddOn override fun getDbVersion(): Int { - return 229 + return 230 } override fun getDbName(): String { @@ -2242,6 +2242,10 @@ open class WellSqlConfig : DefaultWellConfig { 228 -> migrateAddOn(ADDON_WOOCOMMERCE, version) { db.execSQL("DROP TABLE IF EXISTS WCGateways") } + + 229 -> migrateAddOn(ADDON_WOOCOMMERCE, version) { + db.execSQL("DROP TABLE IF EXISTS WCNewVisitorStatsModel") + } } } db.setTransactionSuccessful()