Purpose of the Source of Truth

The Source of Truth serves as the definitive local data source for your app. It provides:

  • Data Consistency: Ensures that all parts of your application refer to a single, consistent data source.
  • Offline Support: Enables your app to function without network connectivity by relying on locally persisted data.
  • Synchronization: Bridges the gap between network data and local storage, ensuring that updates from the network are reflected in the local data source.
  • Observability: Enables the Store to observe changes in the local data source and update consumers accordingly.

APIs

SourceOfTruth

SourceOfTruth has the following structure:

interface SourceOfTruth<Key : Any, Local : Any, Output : Any> {
    fun reader(key: Key): Flow<Output?>
    suspend fun write(key: Key, value: Local)
    suspend fun delete(key: Key)
    suspend fun deleteAll()
}
Key
Any
required

The type representing the key used to identify the data item.

Local
Any
required

The type representing the local database model representation of the item being retrieved.

Output
Any
required

The type representing the domain data model representation of the item being retrieved.

reader

Reads data from the local data source for a given key. Returns a cold Flow emitting the domain data model associated with the key.

key
Key
required

The unique key identifying the data item to be retrieved.

write

Writes data to the local data source for a given key.

key
Key
required

The unique key identifying the data item.

value
Local
required

The data to be written, in the local data source format.

This method is used by RealStore to write data fetched from the network into local storage. It’s also used by the MutableStore to optimistically update the local data source when a write request is received.

delete

Deletes a specific data item from the local data source.

key
Key
required

The unique key identifying the data item to be deleted.

deleteAll

Deletes all data items from the local data source.

Data Flow

Writing Data from Fetcher to Source of Truth

1

Network Fetch

The Store fetches data from the network using the Fetcher.

val networkData = fetcher.fetch(key)
2

Write to Source of Truth

The fetched data is written to the Source of Truth using the write method.

sourceOfTruth.write(key, networkData)
3

Notify Readers

Any active reader observing the key is notified of the new data.

Reading Data from Source of Truth

1

Initiate Read

The consumer requests data from the Store.

val request = StoreReadRequest.cached(key, refresh)
val flow = store.stream(request)
2

Source of Truth Reader

The Store invokes the reader method of the Source of Truth.

val localDataFlow = sourceOfTruth.reader(key)
3

Data Emission

The Source of Truth emits data through the Flow returned by the reader method, which the Store passes to the consumer.

Handling Write and Read Synchronization

The Store uses a SourceOfTruthWithBarrier to synchronize read and write operations. This prevents race conditions and ensures data consistency.

  • Barriers: Implemented using MutableStateFlow to block reads while a write is in progress.
  • Versioning: Each read and write operation carries a version to coordinate updates accurately.

Best Practices

  • Use Observable Storage When Possible: Implement the reader method to return a Flow for real-time data updates.

  • Handle Exceptions Gracefully: Ensure that exceptions are handled appropriately in both the write and reader methods.

  • Convert Between Data Types: Ensure proper conversion between network, local, and domain data types.