refactor(database): split out JVM and Android parts

This commit is contained in:
Harsh Shandilya 2023-09-26 16:19:46 +05:30
parent 1b1984064c
commit 7b0b206905
No known key found for this signature in database
31 changed files with 33 additions and 19 deletions

View file

@ -0,0 +1,7 @@
<!--
~ Copyright © 2021-2023 Harsh Shandilya.
~ Use of this source code is governed by an MIT-style
~ license that can be found in the LICENSE file or at
~ https://opensource.org/licenses/MIT.
-->
<manifest />

View file

@ -0,0 +1,97 @@
/*
* Copyright © 2023 Harsh Shandilya.
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/
package dev.msfjarvis.claw.database
import dev.msfjarvis.claw.database.local.SavedPost
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.descriptors.element
import kotlinx.serialization.encoding.CompositeDecoder
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.encoding.decodeStructure
import kotlinx.serialization.encoding.encodeStructure
@OptIn(ExperimentalSerializationApi::class)
object SavedPostSerializer : KSerializer<SavedPost> {
private val delegateSerializer = ListSerializer(String.serializer())
override val descriptor: SerialDescriptor =
buildClassSerialDescriptor("SavedPost") {
element<String>("shortId")
element<String>("title")
element<String>("url")
element<String>("createdAt")
element<Int?>("commentCount", isOptional = true)
element<String>("commentsUrl")
element<String>("submitterName")
element<String>("submitterAvatarUrl")
element<List<String>>("tags")
element<String>("description")
}
override fun deserialize(decoder: Decoder): SavedPost {
return decoder.decodeStructure(descriptor) {
var shortId = ""
var title = ""
var url = ""
var createdAt = ""
var commentCount: Int? = null
var commentsUrl = ""
var submitterName = ""
var submitterAvatarUrl = ""
var tags = emptyList<String>()
var description = ""
while (true) {
when (val index = decodeElementIndex(descriptor)) {
0 -> shortId = decodeStringElement(descriptor, 0)
1 -> title = decodeStringElement(descriptor, 1)
2 -> url = decodeStringElement(descriptor, 2)
3 -> createdAt = decodeStringElement(descriptor, 3)
4 -> commentCount = decodeNullableSerializableElement(descriptor, 4, Int.serializer())
5 -> commentsUrl = decodeStringElement(descriptor, 5)
6 -> submitterName = decodeStringElement(descriptor, 6)
7 -> submitterAvatarUrl = decodeStringElement(descriptor, 7)
8 -> tags = decodeSerializableElement(descriptor, 8, delegateSerializer)
9 -> description = decodeStringElement(descriptor, 9)
CompositeDecoder.DECODE_DONE -> break
else -> error("Unexpected index: $index")
}
}
SavedPost(
shortId = shortId,
title = title,
url = url,
createdAt = createdAt,
commentCount = commentCount,
commentsUrl = commentsUrl,
submitterName = submitterName,
submitterAvatarUrl = submitterAvatarUrl,
tags = tags,
description = description,
)
}
}
override fun serialize(encoder: Encoder, value: SavedPost) {
encoder.encodeStructure(descriptor) {
encodeStringElement(descriptor, 0, value.shortId)
encodeStringElement(descriptor, 1, value.title)
encodeStringElement(descriptor, 2, value.url)
encodeStringElement(descriptor, 3, value.createdAt)
encodeNullableSerializableElement(descriptor, 4, Int.serializer(), value.commentCount)
encodeStringElement(descriptor, 5, value.commentsUrl)
encodeStringElement(descriptor, 6, value.submitterName)
encodeStringElement(descriptor, 7, value.submitterAvatarUrl)
encodeSerializableElement(descriptor, 8, delegateSerializer, value.tags)
encodeStringElement(descriptor, 9, value.description)
}
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright © 2021-2023 Harsh Shandilya.
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/
package dev.msfjarvis.claw.database.injection
import android.content.Context
import app.cash.sqldelight.adapter.primitive.IntColumnAdapter
import app.cash.sqldelight.driver.android.AndroidSqliteDriver
import com.deliveryhero.whetstone.app.ApplicationScope
import com.squareup.anvil.annotations.ContributesTo
import com.squareup.anvil.annotations.optional.ForScope
import dagger.Module
import dagger.Provides
import dev.msfjarvis.claw.database.LobstersDatabase
import dev.msfjarvis.claw.database.local.PostComments
import dev.msfjarvis.claw.database.local.SavedPost
import dev.msfjarvis.claw.database.model.CSVAdapter
import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
@Module
@ContributesTo(ApplicationScope::class)
object DatabaseModule {
private const val LOBSTERS_DATABASE_NAME = "SavedPosts.db"
@[Provides InternalDatabaseApi]
fun provideDatabase(@ForScope(ApplicationScope::class) context: Context): LobstersDatabase {
val driver =
AndroidSqliteDriver(
schema = LobstersDatabase.Schema,
context = context,
name = LOBSTERS_DATABASE_NAME,
factory = RequerySQLiteOpenHelperFactory(),
)
return LobstersDatabase(
driver = driver,
PostCommentsAdapter = PostComments.Adapter(CSVAdapter()),
SavedPostAdapter = SavedPost.Adapter(IntColumnAdapter, CSVAdapter()),
)
}
}

View file

@ -0,0 +1,19 @@
/*
* Copyright © 2023 Harsh Shandilya.
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/
package dev.msfjarvis.claw.database.injection
import javax.inject.Qualifier
/**
* Neato workaround for not allowing the [dev.msfjarvis.claw.database.LobstersDatabase] type to be
* used directly by modules that depend on this one, as we prefer them to use the specific types
* from [QueriesModule] instead. A [Qualifier] applied to the
* [dev.msfjarvis.claw.database.LobstersDatabase] type makes all injection sites require it as well,
* and marking the annotation class' visibility as `internal` lets it stay visible to the Java code
* generated by Dagger but inaccessible by the Kotlin code we're writing ourselves.
*/
@Qualifier @Retention(AnnotationRetention.RUNTIME) internal annotation class InternalDatabaseApi

View file

@ -0,0 +1,40 @@
/*
* Copyright © 2023 Harsh Shandilya.
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/
package dev.msfjarvis.claw.database.injection
import com.deliveryhero.whetstone.app.ApplicationScope
import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import dev.msfjarvis.claw.database.LobstersDatabase
import dev.msfjarvis.claw.database.local.PostCommentsQueries
import dev.msfjarvis.claw.database.local.ReadPostsQueries
import dev.msfjarvis.claw.database.local.SavedPostQueries
@Module
@ContributesTo(ApplicationScope::class)
object QueriesModule {
@Provides
fun provideSavedPostsQueries(@InternalDatabaseApi database: LobstersDatabase): SavedPostQueries {
return database.savedPostQueries
}
@Provides
fun providePostCommentsQueries(
@InternalDatabaseApi database: LobstersDatabase
): PostCommentsQueries {
return database.postCommentsQueries
}
@Provides
fun provideReadPostsQueries(
@InternalDatabaseApi database: LobstersDatabase,
): ReadPostsQueries {
return database.readPostsQueries
}
}

View file

@ -0,0 +1,23 @@
/*
* Copyright © 2021-2023 Harsh Shandilya.
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/
package dev.msfjarvis.claw.database.model
import app.cash.sqldelight.ColumnAdapter
class CSVAdapter : ColumnAdapter<List<String>, String> {
override fun decode(databaseValue: String): List<String> {
return databaseValue.split(SEPARATOR)
}
override fun encode(value: List<String>): String {
return value.joinToString(SEPARATOR)
}
private companion object {
private const val SEPARATOR = ","
}
}