Add room database.

This commit is contained in:
Thomas Andres Gomez 2021-05-11 12:06:13 +02:00
parent 2ad8d5953a
commit 6a0710572a
17 changed files with 362 additions and 4 deletions

View file

@ -1,6 +1,7 @@
plugins { plugins {
id 'com.android.application' id 'com.android.application'
id 'kotlin-android' id 'kotlin-android'
id 'kotlin-kapt'
id 'org.jetbrains.kotlin.android' id 'org.jetbrains.kotlin.android'
} }
@ -102,6 +103,14 @@ dependencies {
implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.code.gson:gson:2.8.6'
// Room
implementation "androidx.room:room-runtime:2.3.0"
implementation "androidx.room:room-ktx:2.3.0"
kapt "androidx.room:room-compiler:2.3.0"
// Paging
implementation "androidx.paging:paging-runtime-ktx:3.0.0"
// Test // Test
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.0.0-beta06" androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.0.0-beta06"

View file

@ -3,8 +3,10 @@ package com.pixelized.biblib
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.room.Room
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import com.pixelized.biblib.database.BibLibDatabase
import com.pixelized.biblib.network.client.BibLibClient import com.pixelized.biblib.network.client.BibLibClient
import com.pixelized.biblib.network.client.IBibLibClient import com.pixelized.biblib.network.client.IBibLibClient
import com.pixelized.biblib.repository.apiCache.APICacheRepository import com.pixelized.biblib.repository.apiCache.APICacheRepository
@ -21,18 +23,23 @@ class BibLibApplication : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
// Android.
Bob[BibLibDatabase::class] =
Room.databaseBuilder(this, BibLibDatabase::class.java, BibLibDatabase.DATABASE_NAME)
.build()
Bob[SharedPreferences::class] = getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE) Bob[SharedPreferences::class] = getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE)
// Web service.
Bob[Gson::class] = GsonBuilder().create() Bob[Gson::class] = GsonBuilder().create()
Bob[BitmapCache::class] = BitmapCache(this)
Bob[IBibLibClient::class] = BibLibClient() Bob[IBibLibClient::class] = BibLibClient()
// Bitmap cache.
Bob[BitmapCache::class] = BitmapCache(this)
// Repositories.
Bob[IGoogleSingInRepository::class] = GoogleSingInRepository(this) Bob[IGoogleSingInRepository::class] = GoogleSingInRepository(this)
Bob[ICredentialRepository::class] = CredentialRepository() Bob[ICredentialRepository::class] = CredentialRepository()
Bob[IAPICacheRepository::class] = APICacheRepository() Bob[IAPICacheRepository::class] = APICacheRepository()
} }
companion object { companion object {
const val SHARED_PREF = "BIB_LIB_SHARED_PREF" private const val SHARED_PREF = "BIB_LIB_SHARED_PREF"
} }
} }

View file

@ -0,0 +1,37 @@
package com.pixelized.biblib.database
import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.pixelized.biblib.database.converter.DateConverter
import com.pixelized.biblib.database.crossref.BookAuthorCrossRef
import com.pixelized.biblib.database.crossref.BookGenreCrossRef
import com.pixelized.biblib.database.dao.*
import com.pixelized.biblib.database.data.*
@Database(
entities = [
AuthorDbo::class,
BookDbo::class,
GenreDbo::class,
LanguageDbo::class,
SeriesDbo::class,
BookAuthorCrossRef::class,
BookGenreCrossRef::class,
],
version = BibLibDatabase.VERSION
)
@TypeConverters(DateConverter::class)
abstract class BibLibDatabase : RoomDatabase() {
abstract fun authorDao(): AuthorDao
abstract fun bookDao(): BookDao
abstract fun genreDao(): GenreDao
abstract fun languageDao(): LanguageDao
abstract fun seriesDao(): SeriesDao
companion object {
const val VERSION = 1
const val DATABASE_NAME = "BibLibDataBase"
}
}

View file

@ -0,0 +1,12 @@
package com.pixelized.biblib.database.converter
import androidx.room.TypeConverter
import java.util.*
class DateConverter {
@TypeConverter
fun fromTimestamp(value: Long?): Date? = value?.let { Date(it) }
@TypeConverter
fun dateToTimestamp(date: Date?): Long? = date?.time
}

View file

@ -0,0 +1,14 @@
package com.pixelized.biblib.database.crossref
import androidx.room.ColumnInfo
import androidx.room.Entity
import com.pixelized.biblib.database.data.AuthorDbo
import com.pixelized.biblib.database.data.BookDbo
@Entity(primaryKeys = [BookDbo.ID, AuthorDbo.ID])
data class BookAuthorCrossRef(
@ColumnInfo(name = BookDbo.ID)
val bookId: String,
@ColumnInfo(name = AuthorDbo.ID)
val authorId: String
)

View file

@ -0,0 +1,14 @@
package com.pixelized.biblib.database.crossref
import androidx.room.ColumnInfo
import androidx.room.Entity
import com.pixelized.biblib.database.data.BookDbo
import com.pixelized.biblib.database.data.GenreDbo
@Entity(primaryKeys = [BookDbo.ID, GenreDbo.ID])
data class BookGenreCrossRef(
@ColumnInfo(name = BookDbo.ID)
val bookId: String,
@ColumnInfo(name = GenreDbo.ID)
val genreId: String
)

View file

@ -0,0 +1,16 @@
package com.pixelized.biblib.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.pixelized.biblib.database.data.AuthorDbo
@Dao
interface AuthorDao {
@Query("SELECT * FROM ${AuthorDbo.TABLE} WHERE ${AuthorDbo.ID} LIKE :id")
fun get(id: String?): AuthorDbo?
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg authors: AuthorDbo)
}

View file

@ -0,0 +1,18 @@
package com.pixelized.biblib.database.dao
import androidx.room.*
import com.pixelized.biblib.database.data.BookDbo
import com.pixelized.biblib.database.relation.BookRelation
@Dao
interface BookDao {
@Transaction
@Query("SELECT * FROM ${BookDbo.TABLE}")
fun getAll(): List<BookRelation>
@Insert
fun update(vararg books: BookDbo)
@Delete
fun delete(book: BookDbo)
}

View file

@ -0,0 +1,16 @@
package com.pixelized.biblib.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.pixelized.biblib.database.data.GenreDbo
@Dao
interface GenreDao {
@Query("SELECT * FROM ${GenreDbo.TABLE} WHERE ${GenreDbo.ID} LIKE :id")
fun get(id: String?): GenreDbo?
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg genres: GenreDbo)
}

View file

@ -0,0 +1,16 @@
package com.pixelized.biblib.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.pixelized.biblib.database.data.LanguageDbo
@Dao
interface LanguageDao {
@Query("SELECT * FROM ${LanguageDbo.TABLE} WHERE ${LanguageDbo.ID} LIKE :id")
fun get(id: String?): LanguageDbo?
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg languages: LanguageDbo)
}

View file

@ -0,0 +1,16 @@
package com.pixelized.biblib.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.pixelized.biblib.database.data.SeriesDbo
@Dao
interface SeriesDao {
@Query("SELECT * FROM ${SeriesDbo.TABLE} WHERE ${SeriesDbo.ID} LIKE :id")
fun get(id: String?): SeriesDbo?
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg series: SeriesDbo)
}

View file

@ -0,0 +1,23 @@
package com.pixelized.biblib.database.data
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = AuthorDbo.TABLE)
data class AuthorDbo(
@PrimaryKey
@ColumnInfo(name = ID)
val id: String,
@ColumnInfo(name = NAME)
val name: String,
@ColumnInfo(name = SORT)
val sort: String,
) {
companion object {
const val TABLE = "AUTHOR"
const val ID = "${TABLE}_ID"
const val NAME = "${TABLE}_NAME"
const val SORT = "${TABLE}_SORT"
}
}

View file

@ -0,0 +1,58 @@
package com.pixelized.biblib.database.data
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.util.*
@Entity(tableName = BookDbo.TABLE)
data class BookDbo(
@PrimaryKey
@ColumnInfo(name = ID)
val id: Int,
@ColumnInfo(name = TITLE)
val title: String,
@ColumnInfo(name = SORT)
val sort: String,
@ColumnInfo(name = HAVE_COVER)
val haveCover: Boolean,
@ColumnInfo(name = RELEASE_DATE)
val releaseDate: Date,
@ColumnInfo(name = LANGUAGE_ID)
val language: String? = null, // one-to-many
@ColumnInfo(name = RATING)
val rating: Int? = null,
// details
@ColumnInfo(name = SERIES_ID)
val series: String? = null, // one-to-many
@ColumnInfo(name = SYNOPSIS)
val synopsis: String? = null,
// source
@ColumnInfo(name = IS_NEW)
val isNew: Boolean = false,
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is BookDbo) return false
if (id != other.id) return false
return true
}
override fun hashCode(): Int {
return id
}
companion object {
const val TABLE = "BOOK"
const val ID = "${TABLE}_ID"
const val TITLE = "${TABLE}_TITLE"
const val SORT = "${TABLE}_SORT"
const val HAVE_COVER = "${TABLE}_HAVE_COVER"
const val RELEASE_DATE = "${TABLE}_RELEASE_DATE"
const val LANGUAGE_ID = "${TABLE}_LANGUAGE_ID"
const val RATING = "${TABLE}_RATING"
const val SERIES_ID = "${TABLE}_SERIES_ID"
const val SYNOPSIS = "${TABLE}_SYNOPSIS"
const val IS_NEW = "${TABLE}_ISNEW"
}
}

View file

@ -0,0 +1,20 @@
package com.pixelized.biblib.database.data
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = GenreDbo.TABLE)
data class GenreDbo(
@PrimaryKey
@ColumnInfo(name = ID)
val id: String,
@ColumnInfo(name = NAME)
val name: String,
) {
companion object {
const val TABLE = "GENRE"
const val ID = "${TABLE}_ID"
const val NAME = "${TABLE}_NAME"
}
}

View file

@ -0,0 +1,21 @@
package com.pixelized.biblib.database.data
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = LanguageDbo.TABLE)
data class LanguageDbo(
@PrimaryKey
@ColumnInfo(name = ID)
val id: String,
@ColumnInfo(name = NAME)
val code: String,
) {
companion object {
const val TABLE = "LANGUAGE"
const val ID = "${TABLE}_ID"
const val NAME = "${TABLE}_NAME"
}
}

View file

@ -0,0 +1,26 @@
package com.pixelized.biblib.database.data
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = SeriesDbo.TABLE)
data class SeriesDbo(
@PrimaryKey
@ColumnInfo(name = ID)
val id: String,
@ColumnInfo(name = NAME)
val name: String,
@ColumnInfo(name = SORT)
val sort: String,
@ColumnInfo(name = INDEX)
val index: Int?,
) {
companion object {
const val TABLE = "SERIES"
const val ID = "${TABLE}_ID"
const val NAME = "${TABLE}_NAME"
const val SORT = "${TABLE}_SORT"
const val INDEX = "${TABLE}_INDEX"
}
}

View file

@ -0,0 +1,35 @@
package com.pixelized.biblib.database.relation
import androidx.room.Embedded
import androidx.room.Junction
import androidx.room.Relation
import com.pixelized.biblib.database.crossref.BookAuthorCrossRef
import com.pixelized.biblib.database.crossref.BookGenreCrossRef
import com.pixelized.biblib.database.data.*
data class BookRelation(
@Embedded
val bookDbo: BookDbo,
@Relation(
parentColumn = BookDbo.ID,
entityColumn = AuthorDbo.ID,
associateBy = Junction(BookAuthorCrossRef::class)
)
val authors: List<AuthorDbo>,
@Relation(
parentColumn = BookDbo.ID,
entityColumn = GenreDbo.ID,
associateBy = Junction(BookGenreCrossRef::class)
)
val genres: List<GenreDbo>,
@Relation(
parentColumn = BookDbo.LANGUAGE_ID,
entityColumn = LanguageDbo.ID
)
val language: LanguageDbo,
@Relation(
parentColumn = BookDbo.SERIES_ID,
entityColumn = SeriesDbo.ID
)
val series: SeriesDbo,
)