mirror of
https://github.com/msfjarvis/compose-lobsters
synced 2025-08-14 12:57:04 +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"
|
kotlin = "1.5.10"
|
||||||
moshix = "0.11.2"
|
moshix = "0.11.2"
|
||||||
retrofit = "2.9.0"
|
retrofit = "2.9.0"
|
||||||
|
sqldelight = "1.5.0"
|
||||||
|
|
||||||
[libraries]
|
[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-lib = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
|
||||||
thirdparty-retrofit-moshiConverter = { module = "com.squareup.retrofit2:converter-moshi", 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-kotlintest-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
|
||||||
testing-mockWebServer = "com.squareup.okhttp3:mockwebserver3-junit4:5.0.0-alpha.2"
|
testing-mockWebServer = "com.squareup.okhttp3:mockwebserver3-junit4:5.0.0-alpha.2"
|
||||||
|
|
|
@ -19,4 +19,6 @@ include(":api")
|
||||||
|
|
||||||
include(":common")
|
include(":common")
|
||||||
|
|
||||||
|
include(":database")
|
||||||
|
|
||||||
include(":desktop")
|
include(":desktop")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue