Skip to content

Add datastore-preferences module#86

Merged
ghackett merged 5 commits into
mainfrom
datastore-preferences-module
Jul 4, 2026
Merged

Add datastore-preferences module#86
ghackett merged 5 commits into
mainfrom
datastore-preferences-module

Conversation

@ghackett

@ghackett ghackett commented Jul 4, 2026

Copy link
Copy Markdown
Member

Summary

Adds a new deployable module, com.episode6.typed2:datastore-preferences, providing type-safe keys for Jetpack DataStore (Preferences flavor).

Design

  • Dedicated async-only key familyDataStoreKey<T, B> is an AsyncKey typealias over new DataStoreValueGetter/DataStoreValueSetter interfaces. DataStore has no synchronous access, so the module's API only accepts these async keys and there is no runBlocking anywhere; the suspend boundary lives in the DataStore<Preferences> extensions (data.first() for reads, androidx's suspend edit {} for writes). No core changes were needed.
  • Succinct builderskey("someInt").int(default = 2) returns a DataStoreKey directly (no .async() on primitives). The builders shadow core's primitive signatures and convert internally with async(EmptyCoroutineContext), so trivial mappers skip the dispatcher hop. Serialization keys compose via core's in GETTER/SETTER variance: key("obj").gson<Foo>().async().
  • SharedPreferences-consistent semantics — null writes remove the entry, contains/remove are name-based (works across value types), and double() stays string-backed like typed2's other stores.
  • DataStoreValue wrapper for state flowsmutableStateFlow(key, scope) returns MutableStateFlow<DataStoreValue<T>>, starting as Uninitialized and emitting Loaded(value) per read, so consumers can distinguish "not read yet" from "key not present" (Loaded(null)). Setting Loaded(null) removes the entry. property(key, scope) keeps the ergonomic nullable shape on top.
  • Also includes get/edit/launchEdit/set/update/remove suspend extensions and flow(key) with a raw-value prefilter so unrelated edits don't re-run expensive mappers.

Testing

Unit tests run against real DataStores on plain JVM (via androidx.datastore:datastore-preferences-core 1.2.1, no Robolectric): builder round-trips, defaults, required(), name-based remove, null-remove semantics, gson composition, raw-androidx interop, and Turbine tests for flow/mutableStateFlow/property. Full ./gradlew check dokkaGenerateHtml passes.

Follow-ups (out of scope)

  • Sample-app DataStore screen (needs the Android androidx.datastore:datastore-preferences artifact + DI wiring)

🤖 Generated with Claude Code

https://claude.ai/code/session_01CXL3oASXZA1pviJnn8nSbL

ghackett and others added 2 commits July 4, 2026 17:03
Adds type-safe key support for Jetpack DataStore (Preferences) via a new
deployable module. DataStoreKey is a dedicated async-only key family
(AsyncKey over new DataStoreValueGetter/Setter interfaces) with succinct
builders that return async keys directly, so no runBlocking is needed
anywhere and primitives don't require an async() call. MutableStateFlow
emissions are wrapped in DataStoreValue (Uninitialized / Loaded) so
consumers can distinguish the uninitialized state from an absent key.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXL3oASXZA1pviJnn8nSbL
Covers key variance / out-of-core key creation, the builder shadowing
pattern, datastore-preferences semantics, DataStore testing gotchas
(real-time IO vs runTest virtual time), and the new-module checklist.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXL3oASXZA1pviJnn8nSbL
@ghackett ghackett marked this pull request as ready for review July 4, 2026 21:35
ghackett and others added 3 commits July 4, 2026 17:36
Adds the module to the Object Serialization and Async Support sections
of the docs landing page, completing its representation in every
relevant section alongside the existing stores.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXL3oASXZA1pviJnn8nSbL
Adds a DataStore screen to the sample app (mirroring the SharedPref
screen) with a Hilt-provided DataStore<Preferences>, plus an
instrumented test mirroring SharedPrefInstrumentedTest. Backfills an
"Observing Keys as Flows" section in the usage docs covering the flow()
extensions on SharedPreferences, DataStore and SavedStateHandle.

androidx.datastore 1.2+ requires minSdk 23, so the datastore-preferences
module and sample-app override the repo's default minSdk 21.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXL3oASXZA1pviJnn8nSbL
Bumps the shared minSdk in buildSrc Config from 21 to 23 (required by
androidx.datastore 1.2) and removes the per-module overrides on
datastore-preferences and sample-app.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXL3oASXZA1pviJnn8nSbL
@ghackett ghackett merged commit 642aa50 into main Jul 4, 2026
3 checks passed
@ghackett ghackett deleted the datastore-preferences-module branch July 4, 2026 22:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant