mirror of
https://github.com/msfjarvis/compose-lobsters
synced 2025-08-13 19:37:00 +05:30
database: initial commit
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
parent
fcfcbfbf92
commit
ce3dd8b7e7
13 changed files with 314 additions and 0 deletions
8
.idea/artifacts/database_jvm.xml
generated
Normal file
8
.idea/artifacts/database_jvm.xml
generated
Normal file
|
@ -0,0 +1,8 @@
|
|||
<component name="ArtifactManager">
|
||||
<artifact type="jar" name="database-jvm">
|
||||
<output-path>$PROJECT_DIR$/database/build/libs</output-path>
|
||||
<root id="archive" name="database-jvm.jar">
|
||||
<element id="module-output" name="Claw.database.jvmMain" />
|
||||
</root>
|
||||
</artifact>
|
||||
</component>
|
1
database/.gitignore
vendored
Normal file
1
database/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/build
|
42
database/build.gradle.kts
Normal file
42
database/build.gradle.kts
Normal file
|
@ -0,0 +1,42 @@
|
|||
plugins {
|
||||
kotlin("multiplatform")
|
||||
id("com.android.library")
|
||||
id("com.squareup.sqldelight") version "1.5.0"
|
||||
}
|
||||
|
||||
kotlin {
|
||||
android()
|
||||
jvm("desktop") { compilations.all { kotlinOptions.jvmTarget = "11" } }
|
||||
sourceSets {
|
||||
val commonMain by getting
|
||||
val commonTest by getting
|
||||
val androidMain by getting {
|
||||
dependencies { implementation(libs.thirdparty.sqldelight.androidDriver) }
|
||||
}
|
||||
val androidTest by getting
|
||||
val desktopMain by getting { dependencies { implementation(libs.thirdparty.sqldelight.jvmDriver) } }
|
||||
val desktopTest by getting {
|
||||
dependencies {
|
||||
implementation(libs.kotlin.coroutines.core)
|
||||
implementation(kotlin("test-junit"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion(30)
|
||||
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
||||
defaultConfig {
|
||||
minSdkVersion(23)
|
||||
targetSdkVersion(30)
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
}
|
||||
|
||||
configure<com.squareup.sqldelight.gradle.SqlDelightExtension> {
|
||||
database("LobstersDatabase") {
|
||||
packageName = "dev.msfjarvis.lobsters.database"
|
||||
sourceFolders = listOf("sqldelight")
|
||||
}
|
||||
}
|
1
database/consumer-rules.pro
Normal file
1
database/consumer-rules.pro
Normal file
|
@ -0,0 +1 @@
|
|||
-keep class dev.msfjarvis.lobsters.model.** { *; }
|
4
database/src/androidMain/AndroidManifest.xml
Normal file
4
database/src/androidMain/AndroidManifest.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="dev.msfjarvis.lobsters.database"
|
||||
/>
|
|
@ -0,0 +1,12 @@
|
|||
package dev.msfjarvis.lobsters.data.local
|
||||
|
||||
import android.content.Context
|
||||
import com.squareup.sqldelight.android.AndroidSqliteDriver
|
||||
import com.squareup.sqldelight.db.SqlDriver
|
||||
import dev.msfjarvis.lobsters.database.LobstersDatabase
|
||||
|
||||
actual class DriverFactory(private val context: Context) {
|
||||
actual fun createDriver(): SqlDriver {
|
||||
return AndroidSqliteDriver(LobstersDatabase.Schema, context, LobstersDatabaseName)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package dev.msfjarvis.lobsters.data.local
|
||||
|
||||
import com.squareup.sqldelight.db.SqlDriver
|
||||
import dev.msfjarvis.lobsters.data.model.TagsAdapter
|
||||
import dev.msfjarvis.lobsters.database.LobstersDatabase
|
||||
|
||||
internal const val LobstersDatabaseName = "SavedPosts.db"
|
||||
|
||||
expect class DriverFactory {
|
||||
fun createDriver(): SqlDriver
|
||||
}
|
||||
|
||||
private fun getTagsAdapter() = TagsAdapter()
|
||||
|
||||
fun createDatabase(driverFactory: DriverFactory): LobstersDatabase {
|
||||
val driver = driverFactory.createDriver()
|
||||
return LobstersDatabase(driver, SavedPost.Adapter(getTagsAdapter()))
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package dev.msfjarvis.lobsters.data.model
|
||||
|
||||
import com.squareup.sqldelight.ColumnAdapter
|
||||
|
||||
class TagsAdapter : 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 = ","
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
import kotlin.collections.List;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS SavedPost(
|
||||
shortId TEXT NOT NULL PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
createdAt TEXT NOT NULL,
|
||||
commentsUrl TEXT NOT NULL,
|
||||
submitterName TEXT NOT NULL,
|
||||
submitterAvatarUrl TEXT NOT NULL,
|
||||
tags TEXT AS List<String> NOT NULL
|
||||
);
|
||||
|
||||
insertOrReplacePost:
|
||||
INSERT OR REPLACE
|
||||
INTO SavedPost
|
||||
VALUES ?;
|
||||
|
||||
selectAllPosts:
|
||||
SELECT *
|
||||
FROM SavedPost;
|
||||
|
||||
selectCount:
|
||||
SELECT COUNT(*)
|
||||
FROM SavedPost;
|
||||
|
||||
deleteAllPosts:
|
||||
DELETE
|
||||
FROM SavedPost;
|
||||
|
||||
deletePost:
|
||||
DELETE
|
||||
FROM SavedPost
|
||||
WHERE shortId = ?;
|
||||
|
||||
selectPost:
|
||||
SELECT *
|
||||
FROM SavedPost
|
||||
WHERE shortId = ?;
|
|
@ -0,0 +1,13 @@
|
|||
package dev.msfjarvis.lobsters.data.local
|
||||
|
||||
import com.squareup.sqldelight.db.SqlDriver
|
||||
import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver
|
||||
import dev.msfjarvis.lobsters.database.LobstersDatabase
|
||||
|
||||
actual class DriverFactory {
|
||||
actual fun createDriver(): SqlDriver {
|
||||
val driver: SqlDriver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)
|
||||
LobstersDatabase.Schema.create(driver)
|
||||
return driver
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
package dev.msfjarvis.lobsters.data.local
|
||||
|
||||
import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver
|
||||
import dev.msfjarvis.lobsters.data.model.TagsAdapter
|
||||
import dev.msfjarvis.lobsters.database.LobstersDatabase
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Before
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
class SqlDelightQueriesTest {
|
||||
|
||||
private lateinit var postQueries: SavedPostQueries
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
val driver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)
|
||||
LobstersDatabase.Schema.create(driver)
|
||||
val database =
|
||||
LobstersDatabase(
|
||||
driver,
|
||||
SavedPost.Adapter(TagsAdapter()),
|
||||
)
|
||||
postQueries = database.savedPostQueries
|
||||
}
|
||||
|
||||
@Test
|
||||
fun selectCount() = runBlocking {
|
||||
val posts = createTestData(5)
|
||||
|
||||
posts.forEach { postQueries.insertOrReplacePost(it) }
|
||||
|
||||
val postCount = postQueries.selectCount().executeAsOne()
|
||||
assertEquals(5, postCount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun insertIntoDatabase() = runBlocking {
|
||||
// Get 5 posts
|
||||
val posts = createTestData(5)
|
||||
|
||||
// Insert posts into DB
|
||||
posts.forEach { postQueries.insertOrReplacePost(it) }
|
||||
|
||||
// Check post count
|
||||
val postsCount = postQueries.selectCount().executeAsOne()
|
||||
assertEquals(5, postsCount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun replaceFromDatabase() = runBlocking {
|
||||
// Get 1 post
|
||||
val post = createTestData(1)[0]
|
||||
|
||||
// Insert post into DB
|
||||
postQueries.insertOrReplacePost(post)
|
||||
|
||||
// Create a new post and try replacing it
|
||||
val newPost = post.copy(submitterName = "Fake name")
|
||||
postQueries.insertOrReplacePost(newPost)
|
||||
|
||||
// Check post count
|
||||
val postsCount = postQueries.selectCount().executeAsOne()
|
||||
assertEquals(1, postsCount)
|
||||
|
||||
// Check if post is updated
|
||||
val postFromDb = postQueries.selectPost(post.shortId).executeAsOne()
|
||||
assertEquals("Fake name", postFromDb.submitterName)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun selectPost() = runBlocking {
|
||||
// Get 1 post
|
||||
val post = createTestData(1)[0]
|
||||
|
||||
// Insert post into DB
|
||||
postQueries.insertOrReplacePost(post)
|
||||
|
||||
val postFromDb = postQueries.selectAllPosts().executeAsOne()
|
||||
assertEquals("test_id_1", postFromDb.shortId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun selectAllPosts() = runBlocking {
|
||||
// Get 5 post
|
||||
val posts = createTestData(5)
|
||||
|
||||
// Insert posts into DB
|
||||
posts.forEach { postQueries.insertOrReplacePost(it) }
|
||||
|
||||
val postsFromDb = postQueries.selectAllPosts().executeAsList()
|
||||
|
||||
// Check if all posts have correct shortId
|
||||
for (i in 1..5) {
|
||||
assertEquals("test_id_$i", postsFromDb[i - 1].shortId)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deletePost() = runBlocking {
|
||||
// Create 3 posts and insert them to DB
|
||||
val posts = createTestData(3)
|
||||
posts.forEach { postQueries.insertOrReplacePost(it) }
|
||||
|
||||
// Delete 2nd post
|
||||
postQueries.deletePost("test_id_2")
|
||||
|
||||
val postsFromDB = postQueries.selectAllPosts().executeAsList()
|
||||
|
||||
// Check if size is 2, and only the correct post is deleted
|
||||
assertEquals(2, postsFromDB.size)
|
||||
assertEquals("test_id_1", postsFromDB[0].shortId)
|
||||
assertEquals("test_id_3", postsFromDB[1].shortId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deleteAllPost() = runBlocking {
|
||||
// Create 5 posts and insert them to DB
|
||||
val posts = createTestData(5)
|
||||
posts.forEach { postQueries.insertOrReplacePost(it) }
|
||||
|
||||
// Delete all posts
|
||||
postQueries.deleteAllPosts()
|
||||
|
||||
val postsCount = postQueries.selectCount().executeAsOne()
|
||||
|
||||
// Check if db is empty
|
||||
assertEquals(0, postsCount)
|
||||
}
|
||||
|
||||
private fun createTestData(count: Int): ArrayList<SavedPost> {
|
||||
val posts = arrayListOf<SavedPost>()
|
||||
|
||||
for (i in 1..count) {
|
||||
val post =
|
||||
SavedPost(
|
||||
shortId = "test_id_$i",
|
||||
createdAt = "0",
|
||||
title = "test",
|
||||
url = "test_url",
|
||||
commentsUrl = "test_comments_url",
|
||||
submitterName = "test_user_$i",
|
||||
submitterAvatarUrl = "test_avatar_url",
|
||||
tags = listOf(),
|
||||
)
|
||||
|
||||
posts.add(post)
|
||||
}
|
||||
|
||||
return posts
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ coroutines = "1.5.0"
|
|||
kotlin = "1.5.10"
|
||||
moshix = "0.11.2"
|
||||
retrofit = "2.9.0"
|
||||
sqldelight = "1.5.0"
|
||||
|
||||
[libraries]
|
||||
|
||||
|
@ -17,5 +18,8 @@ thirdparty-moshix-metadatareflect = { module = "dev.zacsweers.moshix:moshi-metad
|
|||
thirdparty-retrofit-lib = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
|
||||
thirdparty-retrofit-moshiConverter = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofit" }
|
||||
|
||||
thirdparty-sqldelight-jvmDriver = { module = "com.squareup.sqldelight:sqlite-driver", version.ref = "sqldelight" }
|
||||
thirdparty-sqldelight-androidDriver = { module = "com.squareup.sqldelight:android-driver", version.ref = "sqldelight" }
|
||||
|
||||
testing-kotlintest-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
|
||||
testing-mockWebServer = "com.squareup.okhttp3:mockwebserver3-junit4:5.0.0-alpha.2"
|
||||
|
|
|
@ -19,4 +19,6 @@ include(":api")
|
|||
|
||||
include(":common")
|
||||
|
||||
include(":database")
|
||||
|
||||
include(":desktop")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue