Skip to content

Commit faeb1a9

Browse files
Remove fixme. Add unit test.
1 parent cd3a4e3 commit faeb1a9

File tree

3 files changed

+51
-54
lines changed

3 files changed

+51
-54
lines changed

CHANGELOG.md

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# Changelog
22

3-
## 1.10.0
4-
- Add `appMetadata` parameter to `PowerSyncDatabase.connect()` to include application metadata in sync requests. This metadata is merged into sync requests and displayed in PowerSync service logs.
3+
## 1.10.0 (unreleased)
4+
5+
- Add `appMetadata` parameter to `PowerSyncDatabase.connect()` to include application metadata in
6+
sync requests. This metadata is merged into sync requests and displayed in PowerSync service logs.
7+
8+
Note: This requires a PowerSync service version `>=1.17.0` in order for logs to display metadata.
59

610
```kotlin
711
database.connect(
@@ -15,10 +19,12 @@ database.connect(
1519

1620
## 1.9.0
1721

18-
- Updated user agent string formats to allow viewing version distributions in the new PowerSync dashboard.
22+
- Updated user agent string formats to allow viewing version distributions in the new PowerSync
23+
dashboard.
1924
- Sync options: `newClientImplementation` is now the default.
2025
- Make `androidx.sqlite:sqlite-bundled` an API dependency of `:core` to avoid toolchain warnings.
21-
- On Apple platforms, use a websocket protocol as a workaround to clients not supporting backpressure in HTTP response
26+
- On Apple platforms, use a websocket protocol as a workaround to clients not supporting
27+
backpressure in HTTP response
2228
streams.
2329

2430
## 1.8.1
@@ -27,15 +33,19 @@ database.connect(
2733

2834
## 1.8.0
2935

30-
- Refactor SDK: `com.powersync:powersync-core` has an identical API, but now depends on
36+
- Refactor SDK: `com.powersync:powersync-core` has an identical API, but now depends on
3137
`com.powersync:powersync-common` where most logic is implemented.
32-
- __POTENTIALLY BREAKING CHANGE__: If you were injecting a `DatabaseDriverFactory` into Koin or Dagger, note that the
33-
`PowerSyncDatabase()` factory method now takes a more generic `PersistentConnectionFactory`.
34-
- If you're using `PowerSyncDatabase.inMemory`, you explicitly have to import `com.powersync.inMemory` now.
38+
- __POTENTIALLY BREAKING CHANGE__: If you were injecting a `DatabaseDriverFactory` into Koin or
39+
Dagger, note that the
40+
`PowerSyncDatabase()` factory method now takes a more generic `PersistentConnectionFactory`.
41+
- If you're using `PowerSyncDatabase.inMemory`, you explicitly have to import
42+
`com.powersync.inMemory` now.
3543
- Update the PowerSync core extension to version 0.4.8.
36-
- Add the `soft` flag to `disconnectAndClear()` which keeps an internal copy of synced data in the database, allowing
44+
- Add the `soft` flag to `disconnectAndClear()` which keeps an internal copy of synced data in the
45+
database, allowing
3746
faster re-sync if a compatible token is used in the next `connect()` call.
38-
- Add the `clear` parameter to `RawTable` to run a statement helping the core extension clear raw tables.
47+
- Add the `clear` parameter to `RawTable` to run a statement helping the core extension clear raw
48+
tables.
3949

4050
## 1.7.0
4151

common/src/commonIntegrationTest/kotlin/com/powersync/sync/SyncIntegrationTest.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,33 @@ abstract class BaseSyncIntegrationTest(
9595
}
9696
}
9797

98+
@Test
99+
fun useAppMetadata() =
100+
databaseTest {
101+
database.connect(
102+
connector,
103+
options = getOptions(),
104+
appMetadata =
105+
mapOf(
106+
"app_version" to "1.0.0",
107+
),
108+
)
109+
turbineScope(timeout = 10.0.seconds) {
110+
val turbine = database.currentStatus.asFlow().testIn(this)
111+
turbine.waitFor { it.connected }
112+
turbine.cancel()
113+
}
114+
115+
requestedSyncStreams shouldHaveSingleElement {
116+
val meta = it.jsonObject["app_metadata"]!!.jsonObject
117+
meta.keys shouldHaveSingleElement "app_version"
118+
meta.values
119+
.first()
120+
.jsonPrimitive.content shouldBe "1.0.0"
121+
true
122+
}
123+
}
124+
98125
@Test
99126
@OptIn(DelicateCoroutinesApi::class)
100127
fun closesResponseStreamOnDatabaseClose() =

common/src/commonMain/kotlin/com/powersync/sync/StreamingSync.kt

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ internal class StreamingSyncClient(
9494
configureSyncHttpClient(options.userAgent)
9595
config.block(this)
9696
}
97+
9798
is SyncClientConfiguration.ExistingClient -> config.client
9899
}
99100

@@ -305,7 +306,8 @@ internal class StreamingSyncClient(
305306
} else {
306307
// Use RSocket as a fallback to ensure we have backpressure on platforms that don't support it natively.
307308
flow {
308-
val credentials = requireNotNull(connector.getCredentialsCached()) { "Not logged in" }
309+
val credentials =
310+
requireNotNull(connector.getCredentialsCached()) { "Not logged in" }
309311

310312
emitAll(
311313
httpClient.rSocketSyncStream(
@@ -506,52 +508,10 @@ internal class StreamingSyncClient(
506508
}
507509

508510
private suspend fun connect(start: Instruction.EstablishSyncStream) {
509-
// Merge local appMetadata from StreamingSyncClient into the request before sending
510-
val mergedRequest = mergeAppMetadata(start.request)
511-
receiveTextOrBinaryLines(mergedRequest).collect {
511+
receiveTextOrBinaryLines(start.request).collect {
512512
controlInvocations.send(it)
513513
}
514514
}
515-
516-
/**
517-
* FIXME, the Rust implementation does not yet pass app_metadata to the sync instruction
518-
*
519-
* Merges local appMetadata into the request JsonObject.
520-
* If the request already has app_metadata, the local appMetadata will be merged into it
521-
* (with local values taking precedence for duplicate keys).
522-
*/
523-
private fun mergeAppMetadata(request: JsonObject): JsonObject {
524-
if (appMetadata.isEmpty()) {
525-
return request
526-
}
527-
528-
// Convert local appMetadata to JsonObject
529-
val localAppMetadataJson =
530-
JsonObject(
531-
appMetadata.mapValues { (_, value) -> JsonPrimitive(value) },
532-
)
533-
534-
// Get existing app_metadata from request, if any
535-
val existingAppMetadata =
536-
request["app_metadata"] as? JsonObject ?: JsonObject(emptyMap())
537-
538-
// Merge: existing first, then local (local takes precedence)
539-
val mergedAppMetadata =
540-
JsonObject(
541-
buildMap {
542-
putAll(existingAppMetadata)
543-
putAll(localAppMetadataJson)
544-
},
545-
)
546-
547-
// Create new request with merged app_metadata
548-
return JsonObject(
549-
buildMap {
550-
putAll(request)
551-
put("app_metadata", mergedAppMetadata)
552-
},
553-
)
554-
}
555515
}
556516

557517
@LegacySyncImplementation

0 commit comments

Comments
 (0)