From 28384f3d97d3e915f8dabf45b5c15e0bc5d255bf Mon Sep 17 00:00:00 2001 From: Oguz Kocer Date: Mon, 24 Nov 2025 06:46:09 -0500 Subject: [PATCH 1/4] Replace `u64` with `i64` in `wp_mobile_cache` and `wp_mobile` crates Eliminates unnecessary casting between rusqlite's `i64` and our `u64` types. Since rusqlite consistently uses `i64` for all integer operations, aligning our types reduces friction and improves code clarity. Changes: - Change `RowId` inner type from `u64` to `i64` - Remove casting in `RowId`'s `ToSql`, `FromSql`, and conversion implementations - Update migration functions to use `i64` instead of `u64` - Change `FetchResult.total_items` from `Option` to `Option` - Remove unnecessary casts in repository and service code - Update type casts in test code and helper functions --- wp_mobile/src/collection/fetch_result.rs | 2 +- wp_mobile/src/service/posts.rs | 4 +-- wp_mobile_cache/src/entity.rs | 2 +- wp_mobile_cache/src/lib.rs | 29 +++++++++---------- wp_mobile_cache/src/repository/posts.rs | 6 ++-- .../src/repository/term_relationships.rs | 2 +- 6 files changed, 22 insertions(+), 23 deletions(-) diff --git a/wp_mobile/src/collection/fetch_result.rs b/wp_mobile/src/collection/fetch_result.rs index d0f875a2b..9f45c0137 100644 --- a/wp_mobile/src/collection/fetch_result.rs +++ b/wp_mobile/src/collection/fetch_result.rs @@ -10,7 +10,7 @@ pub struct FetchResult { pub entity_ids: Vec, /// Total number of items matching the query (from API) - pub total_items: Option, + pub total_items: Option, /// Total number of pages available (from API) pub total_pages: Option, diff --git a/wp_mobile/src/service/posts.rs b/wp_mobile/src/service/posts.rs index 6ca07cffc..1a17e078e 100644 --- a/wp_mobile/src/service/posts.rs +++ b/wp_mobile/src/service/posts.rs @@ -98,7 +98,7 @@ impl PostService { Ok(FetchResult { entity_ids, - total_items: response.header_map.wp_total().map(|n| n as u64), + total_items: response.header_map.wp_total().map(|n| n as i64), total_pages: response.header_map.wp_total_pages(), current_page: page, }) @@ -305,7 +305,7 @@ mod tests { // Get the table and rowid from the entity_id let table = entity_id.table; - let rowid = entity_id.rowid.0 as i64; + let rowid = entity_id.rowid.0; // Test: Create UpdateHook that matches this entity let matching_hook = UpdateHook { diff --git a/wp_mobile_cache/src/entity.rs b/wp_mobile_cache/src/entity.rs index e2ccbc0c8..1e60a930b 100644 --- a/wp_mobile_cache/src/entity.rs +++ b/wp_mobile_cache/src/entity.rs @@ -153,7 +153,7 @@ mod tests { /// Uses the same value for both row_id and mapped_site_id for convenience. /// In real data, these would be different (row_id is from db_sites table, /// mapped_site_id is from the type-specific table like self_hosted_sites). - fn make_db_site(id: u64) -> DbSite { + fn make_db_site(id: i64) -> DbSite { DbSite { row_id: RowId(id), site_type: DbSiteType::SelfHosted, diff --git a/wp_mobile_cache/src/lib.rs b/wp_mobile_cache/src/lib.rs index 77cd5f47a..cff397785 100644 --- a/wp_mobile_cache/src/lib.rs +++ b/wp_mobile_cache/src/lib.rs @@ -112,16 +112,15 @@ impl TryFrom<&str> for DbTable { } } -uniffi::custom_newtype!(RowId, u64); +uniffi::custom_newtype!(RowId, i64); /// Represents a database row ID (autoincrement field). -/// SQLite rowids are guaranteed to be non-negative, so we use u64. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] -pub struct RowId(pub u64); +pub struct RowId(pub i64); impl ToSql for RowId { fn to_sql(&self) -> rusqlite::Result> { - Ok(ToSqlOutput::from(self.0 as i64)) + Ok(ToSqlOutput::from(self.0)) } } @@ -129,7 +128,7 @@ impl FromSql for RowId { fn column_result(value: rusqlite::types::ValueRef<'_>) -> FromSqlResult { i64::column_result(value).map(|i| { debug_assert!(i >= 0, "RowId should be non-negative, got: {}", i); - RowId(i as u64) + RowId(i) }) } } @@ -137,7 +136,7 @@ impl FromSql for RowId { impl From for RowId { fn from(value: i64) -> Self { debug_assert!(value >= 0, "RowId should be non-negative, got: {}", value); - RowId(value as u64) + RowId(value) } } @@ -164,7 +163,7 @@ impl RowId { impl From for i64 { fn from(row_id: RowId) -> Self { - row_id.0 as i64 + row_id.0 } } @@ -247,7 +246,7 @@ impl WpApiCache { }) } - pub fn perform_migrations(&self) -> Result { + pub fn perform_migrations(&self) -> Result { self.execute(|connection| { let mut mgr = MigrationManager::new(connection)?; mgr.perform_migrations().map_err(SqliteDbError::from) @@ -379,7 +378,7 @@ impl<'a> MigrationManager<'a> { Ok(result > 0) } - pub fn perform_migrations(&mut self) -> SqliteResult { + pub fn perform_migrations(&mut self) -> SqliteResult { if !self.has_migrations_table()? { self.create_migrations_table()?; } @@ -394,10 +393,10 @@ impl<'a> MigrationManager<'a> { } // `.enumerate` will start the indexes from 0, so we need to add `next_migration_id` - self.insert_migration((next_migration_id + index + 1) as u64)?; + self.insert_migration((next_migration_id + index + 1) as i64)?; } - Ok(MIGRATION_QUERIES[next_migration_id..].len() as u64) + Ok(MIGRATION_QUERIES[next_migration_id..].len() as i64) } pub fn create_migrations_table(&self) -> SqliteResult<()> { @@ -408,7 +407,7 @@ impl<'a> MigrationManager<'a> { Ok(()) } - pub fn insert_migration(&mut self, migration_id: u64) -> SqliteResult<()> { + pub fn insert_migration(&mut self, migration_id: i64) -> SqliteResult<()> { let mut insert_migration_query = self .connection .prepare("INSERT INTO _migrations (migration_id) VALUES (?)")?; @@ -508,14 +507,14 @@ mod tests { let mut stmt = connection .prepare("SELECT migration_id FROM _migrations ORDER BY migration_id") .unwrap(); - let migration_ids: Vec = stmt - .query_map([], |row| row.get::<_, u64>(0)) + let migration_ids: Vec = stmt + .query_map([], |row| row.get::<_, i64>(0)) .unwrap() .collect::, _>>() .unwrap(); // Verify migration IDs are sequential and complete - let expected_ids: Vec = (1..=MIGRATION_QUERIES.len() as u64).collect(); + let expected_ids: Vec = (1..=MIGRATION_QUERIES.len() as i64).collect(); assert_eq!( migration_ids, expected_ids, diff --git a/wp_mobile_cache/src/repository/posts.rs b/wp_mobile_cache/src/repository/posts.rs index 9fd0145ca..1c3b3feef 100644 --- a/wp_mobile_cache/src/repository/posts.rs +++ b/wp_mobile_cache/src/repository/posts.rs @@ -696,7 +696,7 @@ impl PostRepository { |row| row.get(0), ) .map_err(SqliteDbError::from)?; - let post_rowid = RowId(post_rowid as u64); + let post_rowid = RowId(post_rowid); // Sync term relationships let term_repo = TermRelationshipRepository; @@ -829,7 +829,7 @@ impl PostRepository { |row| row.get(0), ) .map_err(SqliteDbError::from)?; - let post_rowid = RowId(post_rowid as u64); + let post_rowid = RowId(post_rowid); // Sync term relationships (ViewContext has categories and tags) let term_repo = TermRelationshipRepository; @@ -930,7 +930,7 @@ impl PostRepository { |row| row.get(0), ) .map_err(SqliteDbError::from)?; - let post_rowid = RowId(post_rowid as u64); + let post_rowid = RowId(post_rowid); // No term relationships for EmbedContext (no categories or tags) diff --git a/wp_mobile_cache/src/repository/term_relationships.rs b/wp_mobile_cache/src/repository/term_relationships.rs index a6fda34e4..1488f8538 100644 --- a/wp_mobile_cache/src/repository/term_relationships.rs +++ b/wp_mobile_cache/src/repository/term_relationships.rs @@ -271,7 +271,7 @@ impl TermRelationshipRepository { HashMap::new(), |mut acc: HashMap>, row_result| { let relationship = row_result.map_err(SqliteDbError::from)?; - acc.entry(relationship.object_id.0 as i64) + acc.entry(relationship.object_id.0) .or_default() .push(relationship); Ok::<_, SqliteDbError>(acc) From bdb0920e0670953397dde460b7eed6240a31d578 Mon Sep 17 00:00:00 2001 From: Oguz Kocer Date: Tue, 9 Dec 2025 10:24:19 -0500 Subject: [PATCH 2/4] Fix WpRequestExecutor constructor call in example app The WpRequestExecutor no longer has a zero-argument constructor. Pass an empty interceptor list to use the secondary constructor. --- .../kotlin/rs/wordpress/example/shared/di/AppModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/kotlin/example/composeApp/src/commonMain/kotlin/rs/wordpress/example/shared/di/AppModule.kt b/native/kotlin/example/composeApp/src/commonMain/kotlin/rs/wordpress/example/shared/di/AppModule.kt index 77d931c83..5e22a6b6f 100644 --- a/native/kotlin/example/composeApp/src/commonMain/kotlin/rs/wordpress/example/shared/di/AppModule.kt +++ b/native/kotlin/example/composeApp/src/commonMain/kotlin/rs/wordpress/example/shared/di/AppModule.kt @@ -89,7 +89,7 @@ val selfHostedServiceModule = module { ), delegate = WpApiClientDelegate( authProvider, - requestExecutor = WpRequestExecutor(), + requestExecutor = WpRequestExecutor(emptyList()), middlewarePipeline = WpApiMiddlewarePipeline(emptyList()), appNotifier = EmptyAppNotifier() ), From 2e3f846337cafb4fad9864ffb5692603b1005bef Mon Sep 17 00:00:00 2001 From: Oguz Kocer Date: Tue, 9 Dec 2025 10:25:12 -0500 Subject: [PATCH 3/4] Fix Swift wrapper return type for performMigrations Update return type from UInt64 to Int64 to match the underlying Rust API change from u64 to i64. --- .../swift/Sources/wordpress-api-cache/WordPressApiCache.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/swift/Sources/wordpress-api-cache/WordPressApiCache.swift b/native/swift/Sources/wordpress-api-cache/WordPressApiCache.swift index 6f7ea1713..0fcae4fc3 100644 --- a/native/swift/Sources/wordpress-api-cache/WordPressApiCache.swift +++ b/native/swift/Sources/wordpress-api-cache/WordPressApiCache.swift @@ -20,7 +20,7 @@ public actor WordPressApiCache { self.cache = try WpApiCache(path: path) } - public func performMigrations() async throws -> UInt64 { + public func performMigrations() async throws -> Int64 { try self.cache.performMigrations() } From 815a05d29bb8a00d17317518d554a39f7684e6c2 Mon Sep 17 00:00:00 2001 From: Oguz Kocer Date: Tue, 9 Dec 2025 11:03:17 -0500 Subject: [PATCH 4/4] Fix WpRequestExecutor constructor call in integration tests The WpRequestExecutor no longer has a zero-argument constructor. Pass an empty interceptor list to use the secondary constructor. --- .../kotlin/src/integrationTest/kotlin/IntegrationTestHelpers.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/kotlin/api/kotlin/src/integrationTest/kotlin/IntegrationTestHelpers.kt b/native/kotlin/api/kotlin/src/integrationTest/kotlin/IntegrationTestHelpers.kt index 4b2e65e56..3fbffb0ed 100644 --- a/native/kotlin/api/kotlin/src/integrationTest/kotlin/IntegrationTestHelpers.kt +++ b/native/kotlin/api/kotlin/src/integrationTest/kotlin/IntegrationTestHelpers.kt @@ -60,7 +60,7 @@ fun createTestServiceContext(): TestServiceContext { apiUrlResolver = WpOrgSiteApiUrlResolver(apiRootUrl = ParsedUrl.parse(apiRootUrl)), delegate = WpApiClientDelegate( authProvider, - requestExecutor = WpRequestExecutor(), + requestExecutor = WpRequestExecutor(emptyList()), middlewarePipeline = WpApiMiddlewarePipeline(emptyList()), appNotifier = EmptyAppNotifier() ),