From 540e36533627fa5416eea2ca906a42a5d336a127 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 8 Sep 2025 17:23:09 +0300 Subject: [PATCH 01/15] Refactor: Optimize imports on wc stats store --- .../android/fluxc/store/WCStatsStore.kt | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) 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..e3ca854bc5fe 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 @@ -28,12 +27,9 @@ import org.wordpress.android.fluxc.persistence.WCVisitorStatsSqlUtils 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 @@ -59,11 +55,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 +138,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, @@ -167,7 +166,7 @@ class WCStatsStore @Inject constructor( 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<*>) { @@ -251,7 +250,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 +267,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 +288,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 +299,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 +324,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,7 +336,7 @@ 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, @@ -408,7 +407,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 +449,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 +466,7 @@ class WCStatsStore @Inject constructor( WooResult(entity.toDomainModel()) } - else -> WooResult(WooError(WooErrorType.GENERIC_ERROR, UNKNOWN)) + else -> WooResult(WooError(WooErrorType.GENERIC_ERROR, GenericErrorType.UNKNOWN)) } } } From 13a299a583815ed5f4a2e0411c7686cfceb69662 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 8 Sep 2025 17:24:34 +0300 Subject: [PATCH 02/15] Analysis: Replace order stats error type with enum entries Warning: "'Enum.values()' is recommended to be replaced by 'Enum.entries' since 1.9" --- .../kotlin/org/wordpress/android/fluxc/store/WCStatsStore.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e3ca854bc5fe..1da01dee49f3 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 @@ -150,7 +150,7 @@ 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 } } From eafaa526482abe6cc80c6bb9981236dd45f6c7e0 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 8 Sep 2025 17:25:53 +0300 Subject: [PATCH 03/15] Analysis: Fix unreachable code on get new visitor stats Warning: "Unreachable code" --- .../org/wordpress/android/fluxc/store/WCStatsStore.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 1da01dee49f3..6459a17ae72c 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 @@ -207,7 +207,8 @@ class WCStatsStore @Inject constructor( dataList = visitorStatsModel.dataList ) } - } ?: return mapOf() + } + return mapOf() } fun getNewVisitorStats( @@ -233,7 +234,8 @@ class WCStatsStore @Inject constructor( dataList = visitorStatsModel.dataList ) } - } ?: return mapOf() + } + return mapOf() } private fun getVisitorsMap( From 587a818297d6ba7704be1a0c649b9fe1e7675d13 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 8 Sep 2025 17:27:48 +0300 Subject: [PATCH 04/15] Analysis: Merge call chain to associate on get xyz stats Warning: "Call chain on a collection type may be simplified" --- .../org/wordpress/android/fluxc/store/WCStatsStore.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 6459a17ae72c..209caa3dfb79 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 @@ -517,9 +517,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( @@ -529,9 +529,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( From 10c0c88d462d559e4c3c1e69cf2f3660dee88097 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 8 Sep 2025 17:42:48 +0300 Subject: [PATCH 05/15] Refactor: Reformat wc stats store (test) --- config/detekt/baseline.xml | 15 - .../android/fluxc/store/WCStatsStore.kt | 33 +- .../fluxc/wc/stats/WCStatsStoreTest.kt | 448 ++++++++++++------ 3 files changed, 308 insertions(+), 188 deletions(-) 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/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 209caa3dfb79..621d2052055e 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 @@ -175,7 +175,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 } @@ -340,13 +340,13 @@ class WCStatsStore @Inject constructor( val quantity = getVisitorStatsQuantity(payload.granularity, startDate, endDate) 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 { @@ -356,11 +356,11 @@ class WCStatsStore @Inject constructor( } else { val rowsAffected = WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(result.stats) OnWCStatsChanged( - rowsAffected, - payload.granularity, - result.stats.quantity, - result.stats.date, - result.stats.isCustomField + rowsAffected, + payload.granularity, + result.stats.quantity, + result.stats.date, + result.stats.isCustomField ).also { it.causeOfChange = WCStatsAction.FETCH_NEW_VISITOR_STATS } @@ -498,11 +498,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 ) } } @@ -541,7 +541,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-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt b/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt index 6d0aa24b04f4..8bfcefed91e1 100644 --- a/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt +++ b/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt @@ -54,11 +54,10 @@ import kotlin.test.assertEquals 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 +71,12 @@ class WCStatsStoreTest { @Before fun setUp() { val config = SingleStoreWellSqlConfigForTests( - context, - listOf( - WCRevenueStatsModel::class.java, - WCNewVisitorStatsModel::class.java - ), - WellSqlConfig.ADDON_WOOCOMMERCE + context, + listOf( + WCRevenueStatsModel::class.java, + WCNewVisitorStatsModel::class.java + ), + WellSqlConfig.ADDON_WOOCOMMERCE ) WellSql.init(config) config.reset() @@ -377,9 +376,20 @@ class WCStatsStoreTest { } @Test + @Suppress("LongMethod") fun testFetchCurrentDayRevenueStatsDate() = runBlocking { 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 +400,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 +418,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 +439,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 +462,20 @@ class WCStatsStoreTest { } @Test + @Suppress("LongMethod") fun testFetchCurrentDayRevenueStatsDateSpecificEndDate() = runBlocking { 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 +487,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 +505,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 +526,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 @@ -486,31 +559,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 +601,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" - ) + WCStatsTestUtils.generateSampleRevenueStatsModel( + interval = StatsGranularity.WEEKS.toString(), startDate = "2019-07-07", endDate = "2019-07-09" + ) val curretnWeekGranularity = StatsGranularity.valueOf( currentWeekStatsModel.interval.uppercase( Locale.getDefault() ) ) val currentWeekPayload = FetchRevenueStatsResponsePayload( - site, curretnWeekGranularity, currentWeekStatsModel + site, curretnWeekGranularity, 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, + curretnWeekGranularity, + 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 +648,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 +696,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 +704,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 +744,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()) @@ -699,7 +832,7 @@ class WCStatsStoreTest { // 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" ) WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(defaultDayVisitorStatsModel2) val defaultDayVisitorStats2 = wcStatsStore.getNewVisitorStats(site, StatsGranularity.DAYS) @@ -708,13 +841,13 @@ class WCStatsStoreTest { // Test Scenario - 3: Generate custom stats for same site i.e. isCustomField - true // 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) val customDayVisitorStats = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.DAYS, customDayVisitorStatsModel.quantity, - customDayVisitorStatsModel.endDate, customDayVisitorStatsModel.isCustomField + site, StatsGranularity.DAYS, customDayVisitorStatsModel.quantity, + customDayVisitorStatsModel.endDate, customDayVisitorStatsModel.isCustomField ) assertTrue(customDayVisitorStats.isNotEmpty()) @@ -722,11 +855,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, customDayVisitorStatsModel2.isCustomField ) assertTrue(customDayVisitorStats2.isEmpty()) @@ -734,12 +867,12 @@ 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, customDayVisitorStatsModel3.isCustomField ) assertTrue(customDayVisitorStats3.isEmpty()) @@ -748,22 +881,22 @@ class WCStatsStoreTest { // 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) val customWeekVisitorStats = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, - customWeekVisitorStatsModel.endDate, customWeekVisitorStatsModel.isCustomField + site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, + customWeekVisitorStatsModel.endDate, customWeekVisitorStatsModel.isCustomField ) assertTrue(customWeekVisitorStats.isNotEmpty()) val customDayVisitorStats4 = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.DAYS, customDayVisitorStatsModel.quantity, - customDayVisitorStatsModel.endDate, customDayVisitorStatsModel.isCustomField + site, StatsGranularity.DAYS, customDayVisitorStatsModel.quantity, + customDayVisitorStatsModel.endDate, customDayVisitorStatsModel.isCustomField ) assertTrue(customDayVisitorStats4.isEmpty()) @@ -772,15 +905,15 @@ class WCStatsStoreTest { // 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) val customWeekVisitorStats2 = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.WEEKS, customWeekVisitorStatsModel2.quantity, - customWeekVisitorStatsModel2.endDate, customWeekVisitorStatsModel2.isCustomField + site, StatsGranularity.WEEKS, customWeekVisitorStatsModel2.quantity, + customWeekVisitorStatsModel2.endDate, customWeekVisitorStatsModel2.isCustomField ) assertTrue(customWeekVisitorStats2.isNotEmpty()) assertTrue(customWeekVisitorStats.isNotEmpty()) @@ -792,7 +925,7 @@ class WCStatsStoreTest { // Test Scenario - 1: Generate default visitor stats i.e. isCustomField - false // 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) @@ -807,7 +940,7 @@ class WCStatsStoreTest { // 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" ) WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(defaultWeekVisitorStatsModel2) val defaultWeekVisitorStats2 = wcStatsStore.getNewVisitorStats(site, StatsGranularity.WEEKS) @@ -816,14 +949,14 @@ class WCStatsStoreTest { // Test Scenario - 3: Generate custom stats for same site i.e. isCustomField - true // 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) val customWeekVisitorStats = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, - customWeekVisitorStatsModel.endDate, customWeekVisitorStatsModel.isCustomField + site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, + customWeekVisitorStatsModel.endDate, customWeekVisitorStatsModel.isCustomField ) assertTrue(customWeekVisitorStats.isNotEmpty()) @@ -831,12 +964,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, customWeekVisitorStatsModel2.isCustomField ) assertTrue(customWeekVisitorStats2.isEmpty()) @@ -844,13 +977,13 @@ 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, customWeekVisitorStatsModel3.isCustomField ) assertTrue(customWeekVisitorStats3.isEmpty()) @@ -859,20 +992,21 @@ class WCStatsStoreTest { // 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) val customMonthVisitorStats = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.MONTHS, customMonthVisitorStatsModel.quantity, - customMonthVisitorStatsModel.endDate, customMonthVisitorStatsModel.isCustomField + site, StatsGranularity.MONTHS, customMonthVisitorStatsModel.quantity, + customMonthVisitorStatsModel.endDate, customMonthVisitorStatsModel.isCustomField ) assertTrue(customMonthVisitorStats.isNotEmpty()) val customWeekVisitorStats4 = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, - customWeekVisitorStatsModel.endDate, customWeekVisitorStatsModel.isCustomField + site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, + customWeekVisitorStatsModel.endDate, customWeekVisitorStatsModel.isCustomField ) assertTrue(customWeekVisitorStats4.isEmpty()) @@ -881,15 +1015,15 @@ class WCStatsStoreTest { // 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) val customMonthVisitorStats2 = wcStatsStore.getNewVisitorStats( - site, StatsGranularity.MONTHS, customMonthVisitorStatsModel2.quantity, - customMonthVisitorStatsModel2.endDate, customMonthVisitorStatsModel2.isCustomField + site, StatsGranularity.MONTHS, customMonthVisitorStatsModel2.quantity, + customMonthVisitorStatsModel2.endDate, customMonthVisitorStatsModel2.isCustomField ) assertTrue(customMonthVisitorStats2.isNotEmpty()) assertTrue(customMonthVisitorStats.isNotEmpty()) @@ -909,11 +1043,11 @@ class WCStatsStoreTest { val defaultWeekVisitorStats = wcStatsStore.getNewVisitorStats(site, StatsGranularity.WEEKS) 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 From dafe3c25101d80fec615c494433ff28e88ddb413 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 8 Sep 2025 17:47:36 +0300 Subject: [PATCH 06/15] Refactor: Make getNewVisitorStats suspend functions FYI: This is done in preparation to the subsequent WellSQL to Room table migration. --- .../ui/dashboard/data/StatsRepositoryTests.kt | 5 +++- .../android/fluxc/store/WCStatsStore.kt | 4 ++-- .../fluxc/wc/stats/WCStatsStoreTest.kt | 24 +++++++++---------- 3 files changed, 18 insertions(+), 15 deletions(-) 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..4aa772b10670 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,13 @@ 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 +88,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, false)) + .thenReturn(emptyMap()) whenever(wcStatsStore.fetchRevenueStats(any())).thenReturn(revenueStatsResponse) whenever(wcStatsStore.getRawRevenueStats(eq(defaultSiteModel), eq(granularity), eq(startDate), eq(endDate))) .thenReturn(WCRevenueStatsModel()) 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 621d2052055e..645abfafcd6f 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 @@ -185,7 +185,7 @@ 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, @@ -211,7 +211,7 @@ class WCStatsStore @Inject constructor( return mapOf() } - fun getNewVisitorStats( + suspend fun getNewVisitorStats( granularity: StatsGranularity, startDate: String, endDate: String, diff --git a/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt b/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt index 8bfcefed91e1..cd9b97ee1a36 100644 --- a/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt +++ b/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt @@ -4,7 +4,6 @@ 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 @@ -44,6 +43,7 @@ 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 @@ -377,7 +377,7 @@ class WCStatsStoreTest { @Test @Suppress("LongMethod") - fun testFetchCurrentDayRevenueStatsDate() = runBlocking { + fun testFetchCurrentDayRevenueStatsDate() = test { val plus12SiteDate = SiteModel().apply { timezone = "12" }.let { whenever( mockOrderStatsRestClient.fetchRevenueStats( @@ -463,7 +463,7 @@ class WCStatsStoreTest { @Test @Suppress("LongMethod") - fun testFetchCurrentDayRevenueStatsDateSpecificEndDate() = runBlocking { + fun testFetchCurrentDayRevenueStatsDateSpecificEndDate() = test { val plus12SiteDate = SiteModel().apply { timezone = "12" }.let { whenever( mockOrderStatsRestClient.fetchRevenueStats( @@ -550,7 +550,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 } @@ -819,7 +819,7 @@ class WCStatsStoreTest { @Test @Suppress("LongMethod") - fun testGetVisitorStatsForCurrentDayGranularity() { + fun testGetVisitorStatsForCurrentDayGranularity() = test { // Test Scenario - 1: Generate default visitor stats i.e. isCustomField - false // Get visitor Stats of the same site and granularity and assert not null val defaultDayVisitorStatsModel = WCStatsTestUtils.generateSampleNewVisitorStatsModel() @@ -921,7 +921,7 @@ class WCStatsStoreTest { @Test @Suppress("LongMethod") - fun testGetVisitorStatsForThisWeekGranularity() { + fun testGetVisitorStatsForThisWeekGranularity() = test { // Test Scenario - 1: Generate default visitor stats i.e. isCustomField - false // Get visitor Stats of the same site and granularity and assert not null val defaultWeekVisitorStatsModel = WCStatsTestUtils.generateSampleNewVisitorStatsModel( @@ -1030,7 +1030,7 @@ class WCStatsStoreTest { } @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 // @@ -1051,7 +1051,7 @@ class WCStatsStoreTest { } @Test - fun testFetchBundlesErrorResponse() = runBlocking { + fun testFetchBundlesErrorResponse() = test { val error = WooError( type = WooErrorType.INVALID_RESPONSE, original = GenericErrorType.INVALID_RESPONSE, @@ -1075,7 +1075,7 @@ class WCStatsStoreTest { } @Test - fun testFetchBundlesNullResponse() = runBlocking { + fun testFetchBundlesNullResponse() = test { val response: WooPayload = WooPayload(null) whenever(mockBundleStatsRestClient.fetchBundleStats(any(), any(), any(), any())) @@ -1094,7 +1094,7 @@ class WCStatsStoreTest { } @Test - fun testFetchBundlesSuccessResponse() = runBlocking { + fun testFetchBundlesSuccessResponse() = test { val totals = BundleStatsTotals( itemsSold = 5, netRevenue = 1000.00 @@ -1119,7 +1119,7 @@ class WCStatsStoreTest { } @Test - fun testSuccessfulFetchingVisitorSummaryStats() = runBlocking { + fun testSuccessfulFetchingVisitorSummaryStats() = test { val site = SiteModel().apply { id = 0 } val apiResponse = VisitorStatsSummaryApiResponse( date = "2024-03-01", @@ -1151,7 +1151,7 @@ class WCStatsStoreTest { } @Test - fun testFailedFetchingVisitorSummaryStats() = runBlocking { + fun testFailedFetchingVisitorSummaryStats() = test { val site = SiteModel().apply { id = 0 } whenever( mockOrderStatsRestClient.fetchVisitorStatsSummary( From a9c67c11d8bbde14c37a2052f3ef6cf8d20729c2 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 8 Sep 2025 18:22:25 +0300 Subject: [PATCH 07/15] Cleanup: Remove unnecessary rows affected from on wc stats changed FYI: This is done in preparation to the subsequent WellSQL to Room table migration. --- .../android/ui/dashboard/data/StatsRepositoryTests.kt | 4 +--- .../org/wordpress/android/fluxc/store/WCStatsStore.kt | 6 ++---- 2 files changed, 3 insertions(+), 7 deletions(-) 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 4aa772b10670..b756158320de 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 @@ -72,7 +72,6 @@ class StatsRepositoryTests : BaseUnitTest() { 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 = quantity, date = startDate @@ -114,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 } @@ -153,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/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 645abfafcd6f..9fd848adff33 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 @@ -157,7 +157,6 @@ class WCStatsStore @Inject constructor( // OnChanged events class OnWCStatsChanged( - val rowsAffected: Int, val granularity: StatsGranularity, val quantity: String? = null, val date: String? = null, @@ -349,14 +348,13 @@ class WCStatsStore @Inject constructor( 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) + WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(result.stats) OnWCStatsChanged( - rowsAffected, payload.granularity, result.stats.quantity, result.stats.date, From 13bb637ae03dc303ae1a1e30bac7fc5043465253 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 8 Sep 2025 17:48:16 +0300 Subject: [PATCH 08/15] Refactor: Optimize imports on wc stats store test (and fix typo) --- .../android/fluxc/wc/stats/WCStatsStoreTest.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt b/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt index cd9b97ee1a36..9fc058b22f41 100644 --- a/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt +++ b/libs/fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt @@ -3,7 +3,6 @@ package org.wordpress.android.fluxc.wc.stats import android.app.Application import androidx.test.core.app.ApplicationProvider import com.yarolegovich.wellsql.WellSql -import junit.framework.TestCase.assertFalse import org.hamcrest.CoreMatchers.anyOf import org.hamcrest.CoreMatchers.not import org.hamcrest.MatcherAssert.assertThat @@ -29,7 +28,6 @@ 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 @@ -51,6 +49,7 @@ 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 @@ -604,13 +603,13 @@ class WCStatsStoreTest { WCStatsTestUtils.generateSampleRevenueStatsModel( interval = StatsGranularity.WEEKS.toString(), startDate = "2019-07-07", endDate = "2019-07-09" ) - val curretnWeekGranularity = StatsGranularity.valueOf( + val currentWeekGranularity = StatsGranularity.valueOf( currentWeekStatsModel.interval.uppercase( Locale.getDefault() ) ) val currentWeekPayload = FetchRevenueStatsResponsePayload( - site, curretnWeekGranularity, currentWeekStatsModel + site, currentWeekGranularity, currentWeekStatsModel ) whenever( mockOrderStatsRestClient.fetchRevenueStats( @@ -627,7 +626,7 @@ class WCStatsStoreTest { wcStatsStore.fetchRevenueStats( FetchRevenueStatsPayload( site, - curretnWeekGranularity, + currentWeekGranularity, currentWeekStatsModel.startDate, currentWeekStatsModel.endDate ) @@ -1160,7 +1159,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, From f65dfe2ac0186cb12d984abad95d4e156e0f9544 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 8 Sep 2025 17:56:42 +0300 Subject: [PATCH 09/15] Test: Move wc stats test utils and wc stats store test to fluxc-plugin FYI: This is done in preparation to the subsequent WellSQL to Room table migration. --- .../wordpress/android/fluxc/store}/WCStatsStoreTest.kt | 8 ++++---- .../wordpress/android/fluxc/wc/stats/WCStatsTestUtils.kt | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) rename libs/{fluxc-tests/src/test/java/org/wordpress/android/fluxc/wc/stats => fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store}/WCStatsStoreTest.kt (99%) rename libs/{fluxc-tests/src/test/java => fluxc-plugin/src/testFixtures/kotlin}/org/wordpress/android/fluxc/wc/stats/WCStatsTestUtils.kt (97%) 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 99% 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 9fc058b22f41..ce9c7bcbf3ad 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,4 +1,4 @@ -package org.wordpress.android.fluxc.wc.stats +package org.wordpress.android.fluxc.store import android.app.Application import androidx.test.core.app.ApplicationProvider @@ -37,7 +37,6 @@ import org.wordpress.android.fluxc.network.rest.wpcom.wc.orderstats.VisitorStats 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 @@ -45,6 +44,7 @@ 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 @@ -1113,8 +1113,8 @@ 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 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 97% 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..6d956634e63d 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 @@ -16,6 +16,7 @@ object WCStatsTestUtils { /** * Generates a sample [WCRevenueStatsModel] */ + @Suppress("MagicNumber") fun generateSampleRevenueStatsModel( localSiteId: Int = 6, interval: String = StatsGranularity.DAYS.toString(), @@ -35,6 +36,7 @@ object WCStatsTestUtils { /** * Generates a sample [WCNewVisitorStatsModel] */ + @Suppress("LongParameterList") fun generateSampleNewVisitorStatsModel( localSiteId: Int = 6, granularity: String = StatsGranularity.DAYS.toString(), From 4f5a86e8131370814d25d1aedc6a02d5bba455d7 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 8 Sep 2025 18:50:07 +0300 Subject: [PATCH 10/15] Migrate: 'WCNewVisitorStatsModel' from wellsql to room FYI: This change includes but is not limited to the: - Entity Introduction - DAO Introduction (With Test) - WCAndroidDatabase Migration - Code Adjustments (Store) - Test Adjustments (Store) --- .../64.json | 3929 +++++++++++++++++ .../android/fluxc/di/WCDatabaseModule.kt | 2 + .../fluxc/model/WCNewVisitorStatsModel.kt | 42 +- .../wc/orderstats/OrderStatsRestClient.kt | 24 +- .../fluxc/persistence/WCAndroidDatabase.kt | 7 +- .../persistence/WCVisitorStatsSqlUtils.kt | 99 - .../persistence/dao/NewVisitorStatsDao.kt | 66 + .../android/fluxc/store/WCStatsStore.kt | 21 +- .../persistence/dao/NewVisitorStatsDaoTest.kt | 189 + .../android/fluxc/store/WCStatsStoreTest.kt | 44 +- .../fluxc/wc/stats/WCStatsTestUtils.kt | 25 +- 11 files changed, 4264 insertions(+), 184 deletions(-) create mode 100644 libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/64.json delete mode 100644 libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCVisitorStatsSqlUtils.kt create mode 100644 libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/NewVisitorStatsDao.kt create mode 100644 libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/persistence/dao/NewVisitorStatsDaoTest.kt diff --git a/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/64.json b/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/64.json new file mode 100644 index 000000000000..4279d0d41a22 --- /dev/null +++ b/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/64.json @@ -0,0 +1,3929 @@ +{ + "formatVersion": 1, + "database": { + "version": 64, + "identityHash": "35f520918095803837d784a6c57114ca", + "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": "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, `isCustomField` INTEGER NOT NULL, `fields` TEXT NOT NULL, `data` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `granularity`, `date`, `quantity`, `isCustomField`))", + "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": "isCustomField", + "columnName": "isCustomField", + "affinity": "INTEGER", + "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", + "isCustomField" + ] + } + } + ], + "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, '35f520918095803837d784a6c57114ca')" + ] + } +} \ 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..6b3e49c908f2 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,26 @@ 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", "isCustomField"], +) +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 isCustomField: Boolean, // to check if the data is for custom stats or default stats + 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 +44,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..b8d661b74700 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,17 @@ 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 ?: "", + isCustomField = startDate != null, + ) 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 216c28790c58..869c558dab59 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 @@ -117,7 +119,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 = 63 +const val WC_DATABASE_VERSION = 64 @Database( version = WC_DATABASE_VERSION, @@ -164,6 +166,7 @@ const val WC_DATABASE_VERSION = 63 WooShippingShipmentEntity::class, WCGlobalAttributeModel::class, GatewayEntity::class, + WCNewVisitorStatsModel::class, ], autoMigrations = [ AutoMigration(from = 12, to = 13), @@ -209,6 +212,7 @@ const val WC_DATABASE_VERSION = 63 AutoMigration(from = 59, to = 60), AutoMigration(from = 60, to = 61), AutoMigration(from = 61, to = 62), + AutoMigration(from = 63, to = 64), ] ) @TypeConverters( @@ -256,6 +260,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..0685531b0f04 --- /dev/null +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/NewVisitorStatsDao.kt @@ -0,0 +1,66 @@ +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 isCustomField = 0 + LIMIT 1 + """ + ) + abstract suspend fun getDefaultStat( + siteId: LocalId, + granularity: StatsGranularity, + ): WCNewVisitorStatsModel? + + @Query( + """ + SELECT * FROM NewVisitorStatsEntity + WHERE localSiteId = :siteId + AND granularity = :granularity + AND date = :date + AND quantity = :quantity + AND isCustomField = 1 + """ + ) + abstract suspend fun getCustomStat( + siteId: LocalId, + granularity: StatsGranularity, + quantity: String?, + date: String?, + ): WCNewVisitorStatsModel? + + @Transaction + open suspend fun insertOrUpdateStat(entity: WCNewVisitorStatsModel) { + return if (entity.isCustomField) { + deleteStatForSite(entity.localSiteId) + insertStat(entity) + } else { + insertStat(entity) + } + } + + @Query( + """ + DELETE FROM NewVisitorStatsEntity + WHERE localSiteId = :siteId + AND isCustomField = 1 + """ + ) + 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 9fd848adff33..a90fa8b2a22e 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 @@ -23,7 +23,7 @@ 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 @@ -35,12 +35,13 @@ 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" @@ -191,9 +192,11 @@ class WCStatsStore @Inject constructor( date: String? = null, isCustomField: Boolean = false ): Map { - val rawStats = WCVisitorStatsSqlUtils.getNewRawVisitorStatsForSiteGranularityQuantityAndDate( - site, granularity, quantity, date, isCustomField - ) + val rawStats = if (isCustomField) { + newVisitorStatsDao.getCustomStat(site.localId(), granularity, quantity, date) + } else { + newVisitorStatsDao.getDefaultStat(site.localId(), granularity) + } rawStats?.let { visitorStatsModel -> val periodIndex = visitorStatsModel.getIndexForField(WCNewVisitorStatsModel.VisitorStatsField.PERIOD) val fieldIndex = visitorStatsModel.getIndexForField(WCNewVisitorStatsModel.VisitorStatsField.VISITORS) @@ -218,8 +221,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.getCustomStat( + site.localId(), granularity, quantity.toString(), date ) rawStats?.let { visitorStatsModel -> val periodIndex = visitorStatsModel.getIndexForField(WCNewVisitorStatsModel.VisitorStatsField.PERIOD) @@ -353,7 +356,7 @@ class WCStatsStore @Inject constructor( it.causeOfChange = WCStatsAction.FETCH_NEW_VISITOR_STATS } } else { - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(result.stats) + newVisitorStatsDao.insertOrUpdateStat(result.stats) OnWCStatsChanged( payload.granularity, result.stats.quantity, 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..e265cb2ed112 --- /dev/null +++ b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/persistence/dao/NewVisitorStatsDaoTest.kt @@ -0,0 +1,189 @@ +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 insert default stat, then getDefaultStat returns it`() = runTest { + val default = defaultDay1Site1 + dao.insertOrUpdateStat(default) + + val retrieved = dao.getDefaultStat(default.localSiteId, StatsGranularity.DAYS) + + assertThat(retrieved).isEqualTo(default) + } + + @Test + fun `given multiple sites & granularities, when insert stats, then getDefaultStat returns correct row`() = runTest { + // Insert different combinations + val defaultSite1Day = defaultDay1Site1 + dao.insertOrUpdateStat(defaultSite1Day) + val defaultSite1Week = defaultWeek1Site1 + dao.insertOrUpdateStat(defaultSite1Week) + val defaultSite2Day = defaultDay1Site2 + dao.insertOrUpdateStat(defaultSite2Day) + + val retrievedSite1Day = dao.getDefaultStat(siteId1, StatsGranularity.DAYS) + val retrievedSite1Week = dao.getDefaultStat(siteId1, StatsGranularity.WEEKS) + val retrievedSite2Day = dao.getDefaultStat(siteId2, StatsGranularity.DAYS) + + assertThat(retrievedSite1Day).isEqualTo(defaultSite1Day) + assertThat(retrievedSite1Week).isEqualTo(defaultSite1Week) + assertThat(retrievedSite2Day).isEqualTo(defaultSite2Day) + } + + @Test + fun `when insert custom stat, then getCustomStat returns by quantity and date`() = runTest { + val custom = customDay1Site1 + dao.insertOrUpdateStat(custom) + + val retrieved = dao.getCustomStat( + custom.localSiteId, + StatsGranularity.DAYS, + custom.quantity, + custom.date + ) + + assertThat(retrieved).isEqualTo(custom) + } + + @Test + fun `when insert custom stat again for same site, then previous custom is deleted`() = runTest { + // Insert first custom + dao.insertOrUpdateStat(customDay1Site1) + // Now insert a second custom for same site (should clear previous custom rows for that site) + dao.insertOrUpdateStat(customDay2Site1) + + // First one should not be found anymore + val first = dao.getCustomStat( + siteId1, + StatsGranularity.DAYS, + customDay1Site1.quantity, + customDay1Site1.date + ) + // Second one should be present + val second = dao.getCustomStat( + siteId1, + StatsGranularity.DAYS, + customDay2Site1.quantity, + customDay2Site1.date + ) + + assertThat(first).isNull() + assertThat(second).isEqualTo(customDay2Site1) + } + + @Test + fun `when insert default stat again for same site, then previous custom is not deleted`() = runTest { + // Have a custom row for site 1 + dao.insertOrUpdateStat(customDay1Site1) + // Insert a default row for same site and granularity + dao.insertOrUpdateStat(defaultDay1Site1) + + // Custom should still be there + val custom = dao.getCustomStat( + siteId1, + StatsGranularity.DAYS, + customDay1Site1.quantity, + customDay1Site1.date + ) + val default = dao.getDefaultStat(siteId1, StatsGranularity.DAYS) + + assertThat(custom).isEqualTo(customDay1Site1) + assertThat(default).isEqualTo(defaultDay1Site1) + } + + companion object { + private val siteId1 = LocalId(1) + private val siteId2 = LocalId(2) + + // Minimal valid payloads for fields and data (stringified JSON) + private const val FIELDS = "[\"period\",\"visitors\"]" + private const val DATA = "[[\"2019-08-01\",1]]" + + // Default stats rows (isCustomField = false) + private val defaultDay1Site1 = WCNewVisitorStatsModel( + localSiteId = siteId1, + granularity = StatsGranularity.DAYS.toString(), + date = "2019-08-01", + startDate = "", + endDate = "", + quantity = "30", + isCustomField = false, + fields = FIELDS, + data = DATA + ) + private val defaultWeek1Site1 = WCNewVisitorStatsModel( + localSiteId = siteId1, + granularity = StatsGranularity.WEEKS.toString(), + date = "2019-08-01", + startDate = "", + endDate = "", + quantity = "12", + isCustomField = false, + fields = FIELDS, + data = DATA + ) + private val defaultDay1Site2 = WCNewVisitorStatsModel( + localSiteId = siteId2, + granularity = StatsGranularity.DAYS.toString(), + date = "2019-08-01", + startDate = "", + endDate = "", + quantity = "30", + isCustomField = false, + fields = FIELDS, + data = DATA + ) + + // Custom stats rows (isCustomField = true) + private val customDay1Site1 = WCNewVisitorStatsModel( + localSiteId = siteId1, + granularity = StatsGranularity.DAYS.toString(), + date = "2019-08-10", + startDate = "2019-08-10", + endDate = "2019-08-10", + quantity = "1", + isCustomField = true, + fields = FIELDS, + data = DATA + ) + private val customDay2Site1 = WCNewVisitorStatsModel( + localSiteId = siteId1, + granularity = StatsGranularity.DAYS.toString(), + date = "2019-08-11", + startDate = "2019-08-11", + endDate = "2019-08-11", + quantity = "1", + isCustomField = true, + fields = FIELDS, + data = DATA + ) + } +} diff --git a/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt index ce9c7bcbf3ad..347fb523cdb9 100644 --- a/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt +++ b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt @@ -22,7 +22,6 @@ 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 @@ -35,7 +34,6 @@ 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.FetchRevenueStatsPayload import org.wordpress.android.fluxc.store.WCStatsStore.FetchRevenueStatsResponsePayload @@ -71,11 +69,8 @@ class WCStatsStoreTest { fun setUp() { val config = SingleStoreWellSqlConfigForTests( context, - listOf( - WCRevenueStatsModel::class.java, - WCNewVisitorStatsModel::class.java - ), - WellSqlConfig.ADDON_WOOCOMMERCE + listOf(WCRevenueStatsModel::class.java), + WellSqlConfig.Companion.ADDON_WOOCOMMERCE ) WellSql.init(config) config.reset() @@ -85,7 +80,8 @@ class WCStatsStoreTest { wcOrderStatsClient = mockOrderStatsRestClient, bundleStatsRestClient = mockBundleStatsRestClient, coroutineEngine = initCoroutineEngine(), - visitorSummaryStatsDao = databaseRule.db.visitorSummaryStatsDao + visitorSummaryStatsDao = databaseRule.db.visitorSummaryStatsDao, + newVisitorStatsDao = databaseRule.db.newVisitorStatsDao, ) } @@ -822,8 +818,8 @@ class WCStatsStoreTest { // Test Scenario - 1: Generate default visitor stats i.e. isCustomField - false // 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.insertOrUpdateStat(defaultDayVisitorStatsModel) val defaultDayVisitorStats = wcStatsStore.getNewVisitorStats(site, StatsGranularity.DAYS) assertTrue(defaultDayVisitorStats.isNotEmpty()) @@ -833,8 +829,8 @@ class WCStatsStoreTest { val defaultDayVisitorStatsModel2 = WCStatsTestUtils.generateSampleNewVisitorStatsModel( endDate = "2019-08-02" ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(defaultDayVisitorStatsModel2) - val defaultDayVisitorStats2 = wcStatsStore.getNewVisitorStats(site, StatsGranularity.DAYS) + databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(defaultDayVisitorStatsModel2) + val defaultDayVisitorStats2 = wcStatsStore.getNewVisitorStats(site, WCStatsStore.StatsGranularity.DAYS) assertTrue(defaultDayVisitorStats2.isNotEmpty()) // Test Scenario - 3: Generate custom stats for same site i.e. isCustomField - true @@ -842,7 +838,7 @@ class WCStatsStoreTest { val customDayVisitorStatsModel = WCStatsTestUtils.generateSampleNewVisitorStatsModel( quantity = "1", endDate = "2019-08-06", startDate = "2019-08-06" ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(customDayVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(customDayVisitorStatsModel) val customDayVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.DAYS, customDayVisitorStatsModel.quantity, @@ -885,7 +881,7 @@ class WCStatsStoreTest { granularity = StatsGranularity.WEEKS.toString() ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(customWeekVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(customWeekVisitorStatsModel) val customWeekVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, @@ -908,7 +904,7 @@ class WCStatsStoreTest { quantity = "1", endDate = "2019-02-01", startDate = "2019-02-01" ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(customWeekVisitorStatsModel2) + databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(customWeekVisitorStatsModel2) val customWeekVisitorStats2 = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, customWeekVisitorStatsModel2.quantity, @@ -926,8 +922,8 @@ class WCStatsStoreTest { val defaultWeekVisitorStatsModel = WCStatsTestUtils.generateSampleNewVisitorStatsModel( 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.insertOrUpdateStat(defaultWeekVisitorStatsModel) val defaultWeekVisitorStats = wcStatsStore.getNewVisitorStats(site, StatsGranularity.WEEKS) assertTrue(defaultWeekVisitorStats.isNotEmpty()) @@ -941,8 +937,8 @@ class WCStatsStoreTest { val defaultWeekVisitorStatsModel2 = WCStatsTestUtils.generateSampleNewVisitorStatsModel( granularity = StatsGranularity.WEEKS.toString(), endDate = "2019-03-20" ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(defaultWeekVisitorStatsModel2) - val defaultWeekVisitorStats2 = wcStatsStore.getNewVisitorStats(site, StatsGranularity.WEEKS) + databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(defaultWeekVisitorStatsModel2) + val defaultWeekVisitorStats2 = wcStatsStore.getNewVisitorStats(site, WCStatsStore.StatsGranularity.WEEKS) assertTrue(defaultWeekVisitorStats2.isNotEmpty()) // Test Scenario - 3: Generate custom stats for same site i.e. isCustomField - true @@ -951,7 +947,7 @@ class WCStatsStoreTest { granularity = StatsGranularity.WEEKS.toString(), quantity = "1", endDate = "2019-08-01", startDate = "2019-08-01" ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(customWeekVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(customWeekVisitorStatsModel) val customWeekVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, @@ -995,7 +991,7 @@ class WCStatsStoreTest { granularity = StatsGranularity.MONTHS.toString() ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(customMonthVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(customMonthVisitorStatsModel) val customMonthVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.MONTHS, customMonthVisitorStatsModel.quantity, @@ -1018,7 +1014,7 @@ class WCStatsStoreTest { quantity = "1", endDate = "2019-08-01", startDate = "2019-08-01" ) - WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(customMonthVisitorStatsModel2) + databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(customMonthVisitorStatsModel2) val customMonthVisitorStats2 = wcStatsStore.getNewVisitorStats( site, StatsGranularity.MONTHS, customMonthVisitorStatsModel2.quantity, @@ -1037,8 +1033,8 @@ 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.insertOrUpdateStat(defaultWeekVisitorStatsModel) val defaultWeekVisitorStats = wcStatsStore.getNewVisitorStats(site, StatsGranularity.WEEKS) assertTrue(defaultWeekVisitorStats.isNotEmpty()) diff --git a/libs/fluxc-plugin/src/testFixtures/kotlin/org/wordpress/android/fluxc/wc/stats/WCStatsTestUtils.kt b/libs/fluxc-plugin/src/testFixtures/kotlin/org/wordpress/android/fluxc/wc/stats/WCStatsTestUtils.kt index 6d956634e63d..8ec9be17c05a 100644 --- a/libs/fluxc-plugin/src/testFixtures/kotlin/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 @@ -46,18 +47,16 @@ 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 ?: "", + isCustomField = startDate != null, + ) } } From 10fbbfbf43627629ae6ab54b36621cac16d9a8a4 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 8 Sep 2025 18:50:55 +0300 Subject: [PATCH 11/15] Db: Drop 'WCNewVisitorStatsModel' table from 'wp-fluxc' --- .../wordpress/android/fluxc/persistence/WellSqlConfig.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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() From 79d96493409d2752b820e78790a92ffbe87a224b Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 12 Sep 2025 12:46:58 +0300 Subject: [PATCH 12/15] Migrate: 'WCNewVisitorStatsModel' from wellsql to room (v2) Due to 146ebde48c24bb0e934a5cb2af97ba990705b6f5 a merge conflict appeared which got solved via 781b01b867c0f7f38b397eb40bd0d24e69696410, with the main '64.json' file, but also a hidden merge conflict on 'WCAndroidDatabase', which includes: - const val WC_DATABASE_VERSION = 65 - AutoMigration(from = 64, to = 65), I accepted the current version of '64.json' and created a new one, the '65.json' because the database version for this exact change has now been updated to '65' (from '64'). --- .../65.json | 3965 +++++++++++++++++ .../fluxc/persistence/WCAndroidDatabase.kt | 3 +- 2 files changed, 3967 insertions(+), 1 deletion(-) create mode 100644 libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/65.json 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..066e8124f946 --- /dev/null +++ b/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/65.json @@ -0,0 +1,3965 @@ +{ + "formatVersion": 1, + "database": { + "version": 65, + "identityHash": "393a829a0cfa848a8a963eebab583366", + "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, `isCustomField` INTEGER NOT NULL, `fields` TEXT NOT NULL, `data` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `granularity`, `date`, `quantity`, `isCustomField`))", + "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": "isCustomField", + "columnName": "isCustomField", + "affinity": "INTEGER", + "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", + "isCustomField" + ] + } + } + ], + "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, '393a829a0cfa848a8a963eebab583366')" + ] + } +} \ No newline at end of file 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 6d797702d305..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 @@ -120,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, @@ -215,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( From e1694cda1905fcf48dcf6e1be15feccc143638e6 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 12 Sep 2025 15:25:06 +0300 Subject: [PATCH 13/15] Cleanup: Remove unnecessary is custom field logic from new visitor stats PR Comment: https://github.com/woocommerce/woocommerce-android/pull/ 14592#pullrequestreview-3212230060 --- .../ui/stats/datasource/StatsRepository.kt | 1 - .../ui/dashboard/data/StatsRepository.kt | 1 - .../ui/dashboard/data/StatsRepositoryTests.kt | 2 +- .../65.json | 15 +--- .../fluxc/model/WCNewVisitorStatsModel.kt | 3 +- .../wc/orderstats/OrderStatsRestClient.kt | 1 - .../persistence/dao/NewVisitorStatsDao.kt | 24 +---- .../android/fluxc/store/WCStatsStore.kt | 11 +-- .../persistence/dao/NewVisitorStatsDaoTest.kt | 88 ------------------- .../android/fluxc/store/WCStatsStoreTest.kt | 70 +++++++++------ .../fluxc/wc/stats/WCStatsTestUtils.kt | 1 - 11 files changed, 54 insertions(+), 163 deletions(-) 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 b756158320de..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 @@ -87,7 +87,7 @@ 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, false)) + 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))) 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 index 066e8124f946..86eb84b17444 100644 --- 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 @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 65, - "identityHash": "393a829a0cfa848a8a963eebab583366", + "identityHash": "2d180f4d4c2ccaf6305a746959d1289d", "entities": [ { "tableName": "AddonEntity", @@ -3888,7 +3888,7 @@ }, { "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, `isCustomField` INTEGER NOT NULL, `fields` TEXT NOT NULL, `data` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `granularity`, `date`, `quantity`, `isCustomField`))", + "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", @@ -3926,12 +3926,6 @@ "affinity": "TEXT", "notNull": true }, - { - "fieldPath": "isCustomField", - "columnName": "isCustomField", - "affinity": "INTEGER", - "notNull": true - }, { "fieldPath": "fields", "columnName": "fields", @@ -3951,15 +3945,14 @@ "localSiteId", "granularity", "date", - "quantity", - "isCustomField" + "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, '393a829a0cfa848a8a963eebab583366')" + "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/model/WCNewVisitorStatsModel.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/model/WCNewVisitorStatsModel.kt index 6b3e49c908f2..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 @@ -8,7 +8,7 @@ import java.util.Locale @Entity( tableName = "NewVisitorStatsEntity", - primaryKeys = ["localSiteId", "granularity", "date", "quantity", "isCustomField"], + primaryKeys = ["localSiteId", "granularity", "date", "quantity"], ) data class WCNewVisitorStatsModel( val localSiteId: LocalId, @@ -17,7 +17,6 @@ data class WCNewVisitorStatsModel( 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 isCustomField: Boolean, // to check if the data is for custom stats or default stats 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 ) { 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 b8d661b74700..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 @@ -210,7 +210,6 @@ class OrderStatsRestClient @Inject constructor( date = date, endDate = endDate ?: "", startDate = startDate ?: "", - isCustomField = startDate != null, ) FetchNewVisitorStatsResponsePayload(site, granularity, model) 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 index 0685531b0f04..0e89ee9b8ed8 100644 --- 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 @@ -11,20 +11,6 @@ import org.wordpress.android.fluxc.store.WCStatsStore.StatsGranularity @Dao internal abstract class NewVisitorStatsDao { - @Query( - """ - SELECT * FROM NewVisitorStatsEntity - WHERE localSiteId = :siteId - AND granularity = :granularity - AND isCustomField = 0 - LIMIT 1 - """ - ) - abstract suspend fun getDefaultStat( - siteId: LocalId, - granularity: StatsGranularity, - ): WCNewVisitorStatsModel? - @Query( """ SELECT * FROM NewVisitorStatsEntity @@ -32,7 +18,6 @@ internal abstract class NewVisitorStatsDao { AND granularity = :granularity AND date = :date AND quantity = :quantity - AND isCustomField = 1 """ ) abstract suspend fun getCustomStat( @@ -44,19 +29,14 @@ internal abstract class NewVisitorStatsDao { @Transaction open suspend fun insertOrUpdateStat(entity: WCNewVisitorStatsModel) { - return if (entity.isCustomField) { - deleteStatForSite(entity.localSiteId) - insertStat(entity) - } else { - insertStat(entity) - } + deleteStatForSite(entity.localSiteId) + insertStat(entity) } @Query( """ DELETE FROM NewVisitorStatsEntity WHERE localSiteId = :siteId - AND isCustomField = 1 """ ) protected abstract suspend fun deleteStatForSite(siteId: LocalId): Int 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 a90fa8b2a22e..962a75150215 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 @@ -161,7 +161,6 @@ class WCStatsStore @Inject internal constructor( val granularity: StatsGranularity, val quantity: String? = null, val date: String? = null, - val isCustomField: Boolean = false ) : OnChanged() { var causeOfChange: WCStatsAction? = null } @@ -189,14 +188,9 @@ class WCStatsStore @Inject internal constructor( site: SiteModel, granularity: StatsGranularity, quantity: String? = null, - date: String? = null, - isCustomField: Boolean = false + date: String? = null ): Map { - val rawStats = if (isCustomField) { - newVisitorStatsDao.getCustomStat(site.localId(), granularity, quantity, date) - } else { - newVisitorStatsDao.getDefaultStat(site.localId(), granularity) - } + val rawStats = newVisitorStatsDao.getCustomStat(site.localId(), granularity, quantity, date) rawStats?.let { visitorStatsModel -> val periodIndex = visitorStatsModel.getIndexForField(WCNewVisitorStatsModel.VisitorStatsField.PERIOD) val fieldIndex = visitorStatsModel.getIndexForField(WCNewVisitorStatsModel.VisitorStatsField.VISITORS) @@ -361,7 +355,6 @@ class WCStatsStore @Inject internal constructor( payload.granularity, result.stats.quantity, result.stats.date, - result.stats.isCustomField ).also { it.causeOfChange = WCStatsAction.FETCH_NEW_VISITOR_STATS } 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 index e265cb2ed112..ecc1d7729655 100644 --- 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 @@ -29,35 +29,6 @@ class NewVisitorStatsDaoTest { dao = databaseRule.db.newVisitorStatsDao } - @Test - fun `when insert default stat, then getDefaultStat returns it`() = runTest { - val default = defaultDay1Site1 - dao.insertOrUpdateStat(default) - - val retrieved = dao.getDefaultStat(default.localSiteId, StatsGranularity.DAYS) - - assertThat(retrieved).isEqualTo(default) - } - - @Test - fun `given multiple sites & granularities, when insert stats, then getDefaultStat returns correct row`() = runTest { - // Insert different combinations - val defaultSite1Day = defaultDay1Site1 - dao.insertOrUpdateStat(defaultSite1Day) - val defaultSite1Week = defaultWeek1Site1 - dao.insertOrUpdateStat(defaultSite1Week) - val defaultSite2Day = defaultDay1Site2 - dao.insertOrUpdateStat(defaultSite2Day) - - val retrievedSite1Day = dao.getDefaultStat(siteId1, StatsGranularity.DAYS) - val retrievedSite1Week = dao.getDefaultStat(siteId1, StatsGranularity.WEEKS) - val retrievedSite2Day = dao.getDefaultStat(siteId2, StatsGranularity.DAYS) - - assertThat(retrievedSite1Day).isEqualTo(defaultSite1Day) - assertThat(retrievedSite1Week).isEqualTo(defaultSite1Week) - assertThat(retrievedSite2Day).isEqualTo(defaultSite2Day) - } - @Test fun `when insert custom stat, then getCustomStat returns by quantity and date`() = runTest { val custom = customDay1Site1 @@ -99,70 +70,13 @@ class NewVisitorStatsDaoTest { assertThat(second).isEqualTo(customDay2Site1) } - @Test - fun `when insert default stat again for same site, then previous custom is not deleted`() = runTest { - // Have a custom row for site 1 - dao.insertOrUpdateStat(customDay1Site1) - // Insert a default row for same site and granularity - dao.insertOrUpdateStat(defaultDay1Site1) - - // Custom should still be there - val custom = dao.getCustomStat( - siteId1, - StatsGranularity.DAYS, - customDay1Site1.quantity, - customDay1Site1.date - ) - val default = dao.getDefaultStat(siteId1, StatsGranularity.DAYS) - - assertThat(custom).isEqualTo(customDay1Site1) - assertThat(default).isEqualTo(defaultDay1Site1) - } - companion object { private val siteId1 = LocalId(1) - private val siteId2 = LocalId(2) // Minimal valid payloads for fields and data (stringified JSON) private const val FIELDS = "[\"period\",\"visitors\"]" private const val DATA = "[[\"2019-08-01\",1]]" - // Default stats rows (isCustomField = false) - private val defaultDay1Site1 = WCNewVisitorStatsModel( - localSiteId = siteId1, - granularity = StatsGranularity.DAYS.toString(), - date = "2019-08-01", - startDate = "", - endDate = "", - quantity = "30", - isCustomField = false, - fields = FIELDS, - data = DATA - ) - private val defaultWeek1Site1 = WCNewVisitorStatsModel( - localSiteId = siteId1, - granularity = StatsGranularity.WEEKS.toString(), - date = "2019-08-01", - startDate = "", - endDate = "", - quantity = "12", - isCustomField = false, - fields = FIELDS, - data = DATA - ) - private val defaultDay1Site2 = WCNewVisitorStatsModel( - localSiteId = siteId2, - granularity = StatsGranularity.DAYS.toString(), - date = "2019-08-01", - startDate = "", - endDate = "", - quantity = "30", - isCustomField = false, - fields = FIELDS, - data = DATA - ) - - // Custom stats rows (isCustomField = true) private val customDay1Site1 = WCNewVisitorStatsModel( localSiteId = siteId1, granularity = StatsGranularity.DAYS.toString(), @@ -170,7 +84,6 @@ class NewVisitorStatsDaoTest { startDate = "2019-08-10", endDate = "2019-08-10", quantity = "1", - isCustomField = true, fields = FIELDS, data = DATA ) @@ -181,7 +94,6 @@ class NewVisitorStatsDaoTest { startDate = "2019-08-11", endDate = "2019-08-11", quantity = "1", - isCustomField = true, fields = FIELDS, data = DATA ) diff --git a/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt index 347fb523cdb9..08cf236c2dfb 100644 --- a/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt +++ b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt @@ -815,13 +815,16 @@ class WCStatsStoreTest { @Test @Suppress("LongMethod") fun testGetVisitorStatsForCurrentDayGranularity() = test { - // Test Scenario - 1: Generate default visitor stats i.e. isCustomField - false + // 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.value } databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(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 @@ -830,10 +833,13 @@ class WCStatsStoreTest { endDate = "2019-08-02" ) databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(defaultDayVisitorStatsModel2) - val defaultDayVisitorStats2 = wcStatsStore.getNewVisitorStats(site, WCStatsStore.StatsGranularity.DAYS) + val defaultDayVisitorStats2 = wcStatsStore.getNewVisitorStats( + site, StatsGranularity.DAYS, defaultDayVisitorStatsModel2.quantity, + defaultDayVisitorStatsModel2.endDate + ) assertTrue(defaultDayVisitorStats2.isNotEmpty()) - // Test Scenario - 3: Generate custom stats for same site i.e. isCustomField - true + // Test Scenario - 3: Generate custom 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" @@ -842,7 +848,7 @@ class WCStatsStoreTest { val customDayVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.DAYS, customDayVisitorStatsModel.quantity, - customDayVisitorStatsModel.endDate, customDayVisitorStatsModel.isCustomField + customDayVisitorStatsModel.endDate ) assertTrue(customDayVisitorStats.isNotEmpty()) @@ -854,7 +860,7 @@ class WCStatsStoreTest { ) val customDayVisitorStats2 = wcStatsStore.getNewVisitorStats( site, StatsGranularity.DAYS, customDayVisitorStatsModel2.quantity, - customDayVisitorStatsModel2.endDate, customDayVisitorStatsModel2.isCustomField + customDayVisitorStatsModel2.endDate ) assertTrue(customDayVisitorStats2.isEmpty()) @@ -867,12 +873,12 @@ class WCStatsStoreTest { val customDayVisitorStats3 = wcStatsStore.getNewVisitorStats( site, StatsGranularity.DAYS, customDayVisitorStatsModel3.quantity, - customDayVisitorStatsModel3.endDate, customDayVisitorStatsModel3.isCustomField + 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( @@ -885,18 +891,18 @@ class WCStatsStoreTest { val customWeekVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, - customWeekVisitorStatsModel.endDate, customWeekVisitorStatsModel.isCustomField + customWeekVisitorStatsModel.endDate ) assertTrue(customWeekVisitorStats.isNotEmpty()) val customDayVisitorStats4 = wcStatsStore.getNewVisitorStats( site, StatsGranularity.DAYS, customDayVisitorStatsModel.quantity, - customDayVisitorStatsModel.endDate, customDayVisitorStatsModel.isCustomField + 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 + // 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( @@ -908,7 +914,7 @@ class WCStatsStoreTest { val customWeekVisitorStats2 = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, customWeekVisitorStatsModel2.quantity, - customWeekVisitorStatsModel2.endDate, customWeekVisitorStatsModel2.isCustomField + customWeekVisitorStatsModel2.endDate ) assertTrue(customWeekVisitorStats2.isNotEmpty()) assertTrue(customWeekVisitorStats.isNotEmpty()) @@ -917,7 +923,7 @@ class WCStatsStoreTest { @Test @Suppress("LongMethod") fun testGetVisitorStatsForThisWeekGranularity() = test { - // Test Scenario - 1: Generate default visitor stats i.e. isCustomField - false + // 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() @@ -925,11 +931,17 @@ class WCStatsStoreTest { val site = SiteModel().apply { id = defaultWeekVisitorStatsModel.localSiteId.value } databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(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 @@ -938,10 +950,13 @@ class WCStatsStoreTest { granularity = StatsGranularity.WEEKS.toString(), endDate = "2019-03-20" ) databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(defaultWeekVisitorStatsModel2) - val defaultWeekVisitorStats2 = wcStatsStore.getNewVisitorStats(site, WCStatsStore.StatsGranularity.WEEKS) + val defaultWeekVisitorStats2 = wcStatsStore.getNewVisitorStats( + site, StatsGranularity.WEEKS, defaultWeekVisitorStatsModel2.quantity, + defaultWeekVisitorStatsModel2.endDate + ) assertTrue(defaultWeekVisitorStats2.isNotEmpty()) - // Test Scenario - 3: Generate custom stats for same site i.e. isCustomField - true + // Test Scenario - 3: Generate custom 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", @@ -951,7 +966,7 @@ class WCStatsStoreTest { val customWeekVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, - customWeekVisitorStatsModel.endDate, customWeekVisitorStatsModel.isCustomField + customWeekVisitorStatsModel.endDate ) assertTrue(customWeekVisitorStats.isNotEmpty()) @@ -964,7 +979,7 @@ class WCStatsStoreTest { ) val customWeekVisitorStats2 = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, customWeekVisitorStatsModel2.quantity, - customWeekVisitorStatsModel2.endDate, customWeekVisitorStatsModel2.isCustomField + customWeekVisitorStatsModel2.endDate ) assertTrue(customWeekVisitorStats2.isEmpty()) @@ -978,12 +993,12 @@ class WCStatsStoreTest { val customWeekVisitorStats3 = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, customWeekVisitorStatsModel3.quantity, - customWeekVisitorStatsModel3.endDate, customWeekVisitorStatsModel3.isCustomField + 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( @@ -995,18 +1010,18 @@ class WCStatsStoreTest { val customMonthVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.MONTHS, customMonthVisitorStatsModel.quantity, - customMonthVisitorStatsModel.endDate, customMonthVisitorStatsModel.isCustomField + customMonthVisitorStatsModel.endDate ) assertTrue(customMonthVisitorStats.isNotEmpty()) val customWeekVisitorStats4 = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, - customWeekVisitorStatsModel.endDate, customWeekVisitorStatsModel.isCustomField + 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 + // 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( @@ -1018,7 +1033,7 @@ class WCStatsStoreTest { val customMonthVisitorStats2 = wcStatsStore.getNewVisitorStats( site, StatsGranularity.MONTHS, customMonthVisitorStatsModel2.quantity, - customMonthVisitorStatsModel2.endDate, customMonthVisitorStatsModel2.isCustomField + customMonthVisitorStatsModel2.endDate ) assertTrue(customMonthVisitorStats2.isNotEmpty()) assertTrue(customMonthVisitorStats.isNotEmpty()) @@ -1036,7 +1051,10 @@ class WCStatsStoreTest { val site = SiteModel().apply { id = defaultWeekVisitorStatsModel.localSiteId.value } databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(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) diff --git a/libs/fluxc-plugin/src/testFixtures/kotlin/org/wordpress/android/fluxc/wc/stats/WCStatsTestUtils.kt b/libs/fluxc-plugin/src/testFixtures/kotlin/org/wordpress/android/fluxc/wc/stats/WCStatsTestUtils.kt index 8ec9be17c05a..e72dde309e88 100644 --- a/libs/fluxc-plugin/src/testFixtures/kotlin/org/wordpress/android/fluxc/wc/stats/WCStatsTestUtils.kt +++ b/libs/fluxc-plugin/src/testFixtures/kotlin/org/wordpress/android/fluxc/wc/stats/WCStatsTestUtils.kt @@ -56,7 +56,6 @@ object WCStatsTestUtils { data = data, date = endDate, startDate = startDate ?: "", - isCustomField = startDate != null, ) } } From ef6197e352700f7455dadaef05737203531b1b3d Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 12 Sep 2025 15:32:15 +0300 Subject: [PATCH 14/15] Cleanup: Remove leftover custom keywork from new visitor stats dao --- .../persistence/dao/NewVisitorStatsDao.kt | 2 +- .../android/fluxc/store/WCStatsStore.kt | 4 +- .../persistence/dao/NewVisitorStatsDaoTest.kt | 44 +++++++++---------- .../android/fluxc/store/WCStatsStoreTest.kt | 8 ++-- 4 files changed, 29 insertions(+), 29 deletions(-) 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 index 0e89ee9b8ed8..b01e7b17024b 100644 --- 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 @@ -20,7 +20,7 @@ internal abstract class NewVisitorStatsDao { AND quantity = :quantity """ ) - abstract suspend fun getCustomStat( + abstract suspend fun getStat( siteId: LocalId, granularity: StatsGranularity, quantity: String?, 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 962a75150215..667013106542 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 @@ -190,7 +190,7 @@ class WCStatsStore @Inject internal constructor( quantity: String? = null, date: String? = null ): Map { - val rawStats = newVisitorStatsDao.getCustomStat(site.localId(), granularity, quantity, date) + 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) @@ -215,7 +215,7 @@ class WCStatsStore @Inject internal constructor( ): Map { val quantity = getVisitorStatsQuantity(granularity, startDate, endDate) val date = DateUtils.getDateTimeForSite(site, DATE_FORMAT_DAY, endDate) - val rawStats = newVisitorStatsDao.getCustomStat( + val rawStats = newVisitorStatsDao.getStat( site.localId(), granularity, quantity.toString(), date ) rawStats?.let { visitorStatsModel -> 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 index ecc1d7729655..4e0feeda1aff 100644 --- 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 @@ -30,44 +30,44 @@ class NewVisitorStatsDaoTest { } @Test - fun `when insert custom stat, then getCustomStat returns by quantity and date`() = runTest { - val custom = customDay1Site1 - dao.insertOrUpdateStat(custom) + fun `when insert stat, then get stat returns by quantity and date`() = runTest { + val stat = statDay1Site1 + dao.insertOrUpdateStat(stat) - val retrieved = dao.getCustomStat( - custom.localSiteId, + val retrieved = dao.getStat( + stat.localSiteId, StatsGranularity.DAYS, - custom.quantity, - custom.date + stat.quantity, + stat.date ) - assertThat(retrieved).isEqualTo(custom) + assertThat(retrieved).isEqualTo(stat) } @Test - fun `when insert custom stat again for same site, then previous custom is deleted`() = runTest { - // Insert first custom - dao.insertOrUpdateStat(customDay1Site1) - // Now insert a second custom for same site (should clear previous custom rows for that site) - dao.insertOrUpdateStat(customDay2Site1) + fun `when insert stat again for same site, then previous stat is deleted`() = runTest { + // Insert first stat + dao.insertOrUpdateStat(statDay1Site1) + // Now insert a second stat for same site (should clear stat rows for that site) + dao.insertOrUpdateStat(statDay2Site1) // First one should not be found anymore - val first = dao.getCustomStat( + val first = dao.getStat( siteId1, StatsGranularity.DAYS, - customDay1Site1.quantity, - customDay1Site1.date + statDay1Site1.quantity, + statDay1Site1.date ) // Second one should be present - val second = dao.getCustomStat( + val second = dao.getStat( siteId1, StatsGranularity.DAYS, - customDay2Site1.quantity, - customDay2Site1.date + statDay2Site1.quantity, + statDay2Site1.date ) assertThat(first).isNull() - assertThat(second).isEqualTo(customDay2Site1) + assertThat(second).isEqualTo(statDay2Site1) } companion object { @@ -77,7 +77,7 @@ class NewVisitorStatsDaoTest { private const val FIELDS = "[\"period\",\"visitors\"]" private const val DATA = "[[\"2019-08-01\",1]]" - private val customDay1Site1 = WCNewVisitorStatsModel( + private val statDay1Site1 = WCNewVisitorStatsModel( localSiteId = siteId1, granularity = StatsGranularity.DAYS.toString(), date = "2019-08-10", @@ -87,7 +87,7 @@ class NewVisitorStatsDaoTest { fields = FIELDS, data = DATA ) - private val customDay2Site1 = WCNewVisitorStatsModel( + private val statDay2Site1 = WCNewVisitorStatsModel( localSiteId = siteId1, granularity = StatsGranularity.DAYS.toString(), date = "2019-08-11", diff --git a/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt index 08cf236c2dfb..2dd3b5723ca5 100644 --- a/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt +++ b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt @@ -839,7 +839,7 @@ class WCStatsStoreTest { ) assertTrue(defaultDayVisitorStats2.isNotEmpty()) - // Test Scenario - 3: Generate custom stats for same site + // 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" @@ -901,7 +901,7 @@ class WCStatsStoreTest { ) assertTrue(customDayVisitorStats4.isEmpty()) - // Test Scenario - 7: Generate custom stats for different site(8) with same granularity(WEEKS), + // 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 @@ -956,7 +956,7 @@ class WCStatsStoreTest { ) assertTrue(defaultWeekVisitorStats2.isNotEmpty()) - // Test Scenario - 3: Generate custom stats for same site + // 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", @@ -1020,7 +1020,7 @@ class WCStatsStoreTest { ) assertTrue(customWeekVisitorStats4.isEmpty()) - // Test Scenario - 7: Generate custom stats for different site(8) with same granularity(MONTHS), + // 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 From 2e112972d4d9684891c57723dec8cd98f5c64746 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 12 Sep 2025 15:34:20 +0300 Subject: [PATCH 15/15] Refactor: Rename insert/update to replace stat on new visitor stats dao --- .../persistence/dao/NewVisitorStatsDao.kt | 2 +- .../android/fluxc/store/WCStatsStore.kt | 2 +- .../persistence/dao/NewVisitorStatsDaoTest.kt | 14 ++++++------ .../android/fluxc/store/WCStatsStoreTest.kt | 22 +++++++++---------- 4 files changed, 20 insertions(+), 20 deletions(-) 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 index b01e7b17024b..371dc0a34e92 100644 --- 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 @@ -28,7 +28,7 @@ internal abstract class NewVisitorStatsDao { ): WCNewVisitorStatsModel? @Transaction - open suspend fun insertOrUpdateStat(entity: WCNewVisitorStatsModel) { + open suspend fun replaceStat(entity: WCNewVisitorStatsModel) { deleteStatForSite(entity.localSiteId) insertStat(entity) } 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 667013106542..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 @@ -350,7 +350,7 @@ class WCStatsStore @Inject internal constructor( it.causeOfChange = WCStatsAction.FETCH_NEW_VISITOR_STATS } } else { - newVisitorStatsDao.insertOrUpdateStat(result.stats) + newVisitorStatsDao.replaceStat(result.stats) OnWCStatsChanged( payload.granularity, result.stats.quantity, 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 index 4e0feeda1aff..c1ad2e785385 100644 --- 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 @@ -30,9 +30,9 @@ class NewVisitorStatsDaoTest { } @Test - fun `when insert stat, then get stat returns by quantity and date`() = runTest { + fun `when replace stat, then get stat returns by quantity and date`() = runTest { val stat = statDay1Site1 - dao.insertOrUpdateStat(stat) + dao.replaceStat(stat) val retrieved = dao.getStat( stat.localSiteId, @@ -45,11 +45,11 @@ class NewVisitorStatsDaoTest { } @Test - fun `when insert stat again for same site, then previous stat is deleted`() = runTest { - // Insert first stat - dao.insertOrUpdateStat(statDay1Site1) - // Now insert a second stat for same site (should clear stat rows for that site) - dao.insertOrUpdateStat(statDay2Site1) + 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( diff --git a/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt index 2dd3b5723ca5..8606ce5a114a 100644 --- a/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt +++ b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/store/WCStatsStoreTest.kt @@ -819,7 +819,7 @@ class WCStatsStoreTest { // Get visitor Stats of the same site and granularity and assert not null val defaultDayVisitorStatsModel = WCStatsTestUtils.generateSampleNewVisitorStatsModel() val site = SiteModel().apply { id = defaultDayVisitorStatsModel.localSiteId.value } - databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(defaultDayVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.replaceStat(defaultDayVisitorStatsModel) val defaultDayVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.DAYS, defaultDayVisitorStatsModel.quantity, @@ -832,7 +832,7 @@ class WCStatsStoreTest { val defaultDayVisitorStatsModel2 = WCStatsTestUtils.generateSampleNewVisitorStatsModel( endDate = "2019-08-02" ) - databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(defaultDayVisitorStatsModel2) + databaseRule.db.newVisitorStatsDao.replaceStat(defaultDayVisitorStatsModel2) val defaultDayVisitorStats2 = wcStatsStore.getNewVisitorStats( site, StatsGranularity.DAYS, defaultDayVisitorStatsModel2.quantity, defaultDayVisitorStatsModel2.endDate @@ -844,7 +844,7 @@ class WCStatsStoreTest { val customDayVisitorStatsModel = WCStatsTestUtils.generateSampleNewVisitorStatsModel( quantity = "1", endDate = "2019-08-06", startDate = "2019-08-06" ) - databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(customDayVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.replaceStat(customDayVisitorStatsModel) val customDayVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.DAYS, customDayVisitorStatsModel.quantity, @@ -887,7 +887,7 @@ class WCStatsStoreTest { granularity = StatsGranularity.WEEKS.toString() ) - databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(customWeekVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.replaceStat(customWeekVisitorStatsModel) val customWeekVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, @@ -910,7 +910,7 @@ class WCStatsStoreTest { quantity = "1", endDate = "2019-02-01", startDate = "2019-02-01" ) - databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(customWeekVisitorStatsModel2) + databaseRule.db.newVisitorStatsDao.replaceStat(customWeekVisitorStatsModel2) val customWeekVisitorStats2 = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, customWeekVisitorStatsModel2.quantity, @@ -929,7 +929,7 @@ class WCStatsStoreTest { granularity = StatsGranularity.WEEKS.toString() ) val site = SiteModel().apply { id = defaultWeekVisitorStatsModel.localSiteId.value } - databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(defaultWeekVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.replaceStat(defaultWeekVisitorStatsModel) val defaultWeekVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, defaultWeekVisitorStatsModel.quantity, @@ -949,7 +949,7 @@ class WCStatsStoreTest { val defaultWeekVisitorStatsModel2 = WCStatsTestUtils.generateSampleNewVisitorStatsModel( granularity = StatsGranularity.WEEKS.toString(), endDate = "2019-03-20" ) - databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(defaultWeekVisitorStatsModel2) + databaseRule.db.newVisitorStatsDao.replaceStat(defaultWeekVisitorStatsModel2) val defaultWeekVisitorStats2 = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, defaultWeekVisitorStatsModel2.quantity, defaultWeekVisitorStatsModel2.endDate @@ -962,7 +962,7 @@ class WCStatsStoreTest { granularity = StatsGranularity.WEEKS.toString(), quantity = "1", endDate = "2019-08-01", startDate = "2019-08-01" ) - databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(customWeekVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.replaceStat(customWeekVisitorStatsModel) val customWeekVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, customWeekVisitorStatsModel.quantity, @@ -1006,7 +1006,7 @@ class WCStatsStoreTest { granularity = StatsGranularity.MONTHS.toString() ) - databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(customMonthVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.replaceStat(customMonthVisitorStatsModel) val customMonthVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.MONTHS, customMonthVisitorStatsModel.quantity, @@ -1029,7 +1029,7 @@ class WCStatsStoreTest { quantity = "1", endDate = "2019-08-01", startDate = "2019-08-01" ) - databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(customMonthVisitorStatsModel2) + databaseRule.db.newVisitorStatsDao.replaceStat(customMonthVisitorStatsModel2) val customMonthVisitorStats2 = wcStatsStore.getNewVisitorStats( site, StatsGranularity.MONTHS, customMonthVisitorStatsModel2.quantity, @@ -1049,7 +1049,7 @@ class WCStatsStoreTest { data = UnitTestUtils.getStringFromResourceFile(this.javaClass, "wc/wrong-visitor-stats-data.json") ) val site = SiteModel().apply { id = defaultWeekVisitorStatsModel.localSiteId.value } - databaseRule.db.newVisitorStatsDao.insertOrUpdateStat(defaultWeekVisitorStatsModel) + databaseRule.db.newVisitorStatsDao.replaceStat(defaultWeekVisitorStatsModel) val defaultWeekVisitorStats = wcStatsStore.getNewVisitorStats( site, StatsGranularity.WEEKS, defaultWeekVisitorStatsModel.quantity,