1
0
mirror of https://github.com/KokaKiwi/BarInsta synced 2024-11-15 19:27:31 +00:00

Convert AppDatabase to kotlin

This commit is contained in:
Ammar Githam 2021-06-08 22:39:00 +09:00
parent 66b60e6830
commit 54ff196bb1
3 changed files with 231 additions and 250 deletions

View File

@ -1,6 +1,7 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: "androidx.navigation.safeargs" apply plugin: "androidx.navigation.safeargs"
apply plugin: 'kotlin-kapt'
apply from: 'sentry.gradle' apply from: 'sentry.gradle'
def getGitHash = { -> def getGitHash = { ->
@ -146,6 +147,7 @@ android {
// Error: Duplicate files during packaging of APK // Error: Duplicate files during packaging of APK
exclude 'META-INF/LICENSE.md' exclude 'META-INF/LICENSE.md'
exclude 'META-INF/LICENSE-notice.md' exclude 'META-INF/LICENSE-notice.md'
exclude 'META-INF/atomicfu.kotlin_module'
} }
testOptions.unitTests { testOptions.unitTests {
@ -196,6 +198,7 @@ dependencies {
implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-runtime:$room_version"
implementation "androidx.room:room-guava:$room_version" implementation "androidx.room:room-guava:$room_version"
implementation "androidx.room:room-ktx:$room_version" implementation "androidx.room:room-ktx:$room_version"
kapt "androidx.room:room-compiler:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version" annotationProcessor "androidx.room:room-compiler:$room_version"
// CameraX // CameraX

View File

@ -1,270 +1,252 @@
package awais.instagrabber.db; package awais.instagrabber.db
import android.content.ContentValues; import android.content.ContentValues
import android.content.Context; import android.content.Context
import android.database.Cursor; import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteDatabase; import android.util.Log
import android.util.Log; import androidx.room.Database
import android.util.Pair; import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import awais.instagrabber.db.dao.AccountDao
import awais.instagrabber.db.dao.DMLastNotifiedDao
import awais.instagrabber.db.dao.FavoriteDao
import awais.instagrabber.db.dao.RecentSearchDao
import awais.instagrabber.db.entities.Account
import awais.instagrabber.db.entities.DMLastNotified
import awais.instagrabber.db.entities.Favorite
import awais.instagrabber.db.entities.RecentSearch
import awais.instagrabber.utils.Utils
import awais.instagrabber.utils.extensions.TAG
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.*
import androidx.annotation.NonNull; @Database(entities = [Account::class, Favorite::class, DMLastNotified::class, RecentSearch::class], version = 6)
import androidx.room.Database; @TypeConverters(Converters::class)
import androidx.room.Room; abstract class AppDatabase : RoomDatabase() {
import androidx.room.RoomDatabase; abstract fun accountDao(): AccountDao
import androidx.room.TypeConverters; abstract fun favoriteDao(): FavoriteDao
import androidx.room.migration.Migration; abstract fun dmLastNotifiedDao(): DMLastNotifiedDao
import androidx.sqlite.db.SupportSQLiteDatabase; abstract fun recentSearchDao(): RecentSearchDao
import java.time.Instant; companion object {
import java.time.LocalDateTime; private lateinit var INSTANCE: AppDatabase
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import awais.instagrabber.db.dao.AccountDao; fun getDatabase(context: Context): AppDatabase {
import awais.instagrabber.db.dao.DMLastNotifiedDao; if (!this::INSTANCE.isInitialized) {
import awais.instagrabber.db.dao.FavoriteDao; synchronized(AppDatabase::class.java) {
import awais.instagrabber.db.dao.RecentSearchDao; if (!this::INSTANCE.isInitialized) {
import awais.instagrabber.db.entities.Account; INSTANCE = Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "cookiebox.db")
import awais.instagrabber.db.entities.DMLastNotified; .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6)
import awais.instagrabber.db.entities.Favorite; .build()
import awais.instagrabber.db.entities.RecentSearch; }
import awais.instagrabber.models.enums.FavoriteType; }
import awais.instagrabber.utils.Utils; }
return INSTANCE
}
@Database(entities = {Account.class, Favorite.class, DMLastNotified.class, RecentSearch.class}, private val MIGRATION_1_2: Migration = object : Migration(1, 2) {
version = 6) override fun migrate(db: SupportSQLiteDatabase) {
@TypeConverters({Converters.class}) db.execSQL("ALTER TABLE cookies ADD " + Account.COL_FULL_NAME + " TEXT")
public abstract class AppDatabase extends RoomDatabase { db.execSQL("ALTER TABLE cookies ADD " + Account.COL_PROFILE_PIC + " TEXT")
private static final String TAG = AppDatabase.class.getSimpleName(); }
}
private static AppDatabase INSTANCE; private val MIGRATION_2_3: Migration = object : Migration(2, 3) {
override fun migrate(db: SupportSQLiteDatabase) {
public abstract AccountDao accountDao(); val oldFavorites = backupOldFavorites(db)
// recreate with new columns (as there will be no doubt about the `query_display` column being present or not in the future versions)
public abstract FavoriteDao favoriteDao(); db.execSQL("DROP TABLE " + Favorite.TABLE_NAME)
db.execSQL("CREATE TABLE " + Favorite.TABLE_NAME + " ("
public abstract DMLastNotifiedDao dmLastNotifiedDao(); + Favorite.COL_ID + " INTEGER PRIMARY KEY,"
+ Favorite.COL_QUERY + " TEXT,"
public abstract RecentSearchDao recentSearchDao(); + Favorite.COL_TYPE + " TEXT,"
+ Favorite.COL_DISPLAY_NAME + " TEXT,"
public static AppDatabase getDatabase(final Context context) { + Favorite.COL_PIC_URL + " TEXT,"
if (INSTANCE == null) { + Favorite.COL_DATE_ADDED + " INTEGER)")
synchronized (AppDatabase.class) { // add the old favorites back
if (INSTANCE == null) { for (oldFavorite in oldFavorites) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "cookiebox.db") insertOrUpdateFavorite(db, oldFavorite)
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6)
.build();
} }
} }
} }
return INSTANCE; private val MIGRATION_3_4: Migration = object : Migration(3, 4) {
} override fun migrate(db: SupportSQLiteDatabase) {
// Required when migrating to Room.
// The original table primary keys were not 'NOT NULL', so the migration to Room were failing without the below migration.
// Taking this opportunity to rename cookies table to accounts
static final Migration MIGRATION_1_2 = new Migration(1, 2) { // Create new table with name 'accounts'
@Override db.execSQL("CREATE TABLE " + Account.TABLE_NAME + " ("
public void migrate(@NonNull SupportSQLiteDatabase db) { + Account.COL_ID + " INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
db.execSQL("ALTER TABLE cookies ADD " + Account.COL_FULL_NAME + " TEXT"); + Account.COL_UID + " TEXT,"
db.execSQL("ALTER TABLE cookies ADD " + Account.COL_PROFILE_PIC + " TEXT"); + Account.COL_USERNAME + " TEXT,"
} + Account.COL_COOKIE + " TEXT,"
}; + Account.COL_FULL_NAME + " TEXT,"
+ Account.COL_PROFILE_PIC + " TEXT)")
// Insert all data from table 'cookies' to 'accounts'
db.execSQL("INSERT INTO " + Account.TABLE_NAME + " ("
+ Account.COL_UID + ","
+ Account.COL_USERNAME + ","
+ Account.COL_COOKIE + ","
+ Account.COL_FULL_NAME + ","
+ Account.COL_PROFILE_PIC + ") "
+ "SELECT "
+ Account.COL_UID + ","
+ Account.COL_USERNAME + ","
+ Account.COL_COOKIE + ","
+ Account.COL_FULL_NAME + ","
+ Account.COL_PROFILE_PIC
+ " FROM cookies")
// Drop old cookies table
db.execSQL("DROP TABLE cookies")
static final Migration MIGRATION_2_3 = new Migration(2, 3) { // Create favorite backup table
@Override db.execSQL("CREATE TABLE " + Favorite.TABLE_NAME + "_backup ("
public void migrate(@NonNull SupportSQLiteDatabase db) { + Favorite.COL_ID + " INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
final List<Favorite> oldFavorites = backupOldFavorites(db); + Favorite.COL_QUERY + " TEXT,"
// recreate with new columns (as there will be no doubt about the `query_display` column being present or not in the future versions) + Favorite.COL_TYPE + " TEXT,"
db.execSQL("DROP TABLE " + Favorite.TABLE_NAME); + Favorite.COL_DISPLAY_NAME + " TEXT,"
db.execSQL("CREATE TABLE " + Favorite.TABLE_NAME + " (" + Favorite.COL_PIC_URL + " TEXT,"
+ Favorite.COL_ID + " INTEGER PRIMARY KEY," + Favorite.COL_DATE_ADDED + " INTEGER)")
+ Favorite.COL_QUERY + " TEXT," // Insert all data from table 'favorite' to 'favorite_backup'
+ Favorite.COL_TYPE + " TEXT," db.execSQL("INSERT INTO " + Favorite.TABLE_NAME + "_backup ("
+ Favorite.COL_DISPLAY_NAME + " TEXT," + Favorite.COL_QUERY + ","
+ Favorite.COL_PIC_URL + " TEXT," + Favorite.COL_TYPE + ","
+ Favorite.COL_DATE_ADDED + " INTEGER)"); + Favorite.COL_DISPLAY_NAME + ","
// add the old favorites back + Favorite.COL_PIC_URL + ","
for (final Favorite oldFavorite : oldFavorites) { + Favorite.COL_DATE_ADDED + ") "
insertOrUpdateFavorite(db, oldFavorite); + "SELECT "
+ Favorite.COL_QUERY + ","
+ Favorite.COL_TYPE + ","
+ Favorite.COL_DISPLAY_NAME + ","
+ Favorite.COL_PIC_URL + ","
+ Favorite.COL_DATE_ADDED
+ " FROM " + Favorite.TABLE_NAME)
// Drop favorites
db.execSQL("DROP TABLE " + Favorite.TABLE_NAME)
// Rename favorite_backup to favorites
db.execSQL("ALTER TABLE " + Favorite.TABLE_NAME + "_backup RENAME TO " + Favorite.TABLE_NAME)
} }
} }
}; private val MIGRATION_4_5: Migration = object : Migration(4, 5) {
override fun migrate(database: SupportSQLiteDatabase) {
static final Migration MIGRATION_3_4 = new Migration(3, 4) { database.execSQL("CREATE TABLE IF NOT EXISTS `dm_last_notified` (" +
@Override "`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
public void migrate(@NonNull SupportSQLiteDatabase db) { "`thread_id` TEXT, " +
// Required when migrating to Room. "`last_notified_msg_ts` INTEGER, " +
// The original table primary keys were not 'NOT NULL', so the migration to Room were failing without the below migration. "`last_notified_at` INTEGER)")
// Taking this opportunity to rename cookies table to accounts database.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_dm_last_notified_thread_id` ON `dm_last_notified` (`thread_id`)")
}
// Create new table with name 'accounts'
db.execSQL("CREATE TABLE " + Account.TABLE_NAME + " ("
+ Account.COL_ID + " INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
+ Account.COL_UID + " TEXT,"
+ Account.COL_USERNAME + " TEXT,"
+ Account.COL_COOKIE + " TEXT,"
+ Account.COL_FULL_NAME + " TEXT,"
+ Account.COL_PROFILE_PIC + " TEXT)");
// Insert all data from table 'cookies' to 'accounts'
db.execSQL("INSERT INTO " + Account.TABLE_NAME + " ("
+ Account.COL_UID + ","
+ Account.COL_USERNAME + ","
+ Account.COL_COOKIE + ","
+ Account.COL_FULL_NAME + ","
+ Account.COL_PROFILE_PIC + ") "
+ "SELECT "
+ Account.COL_UID + ","
+ Account.COL_USERNAME + ","
+ Account.COL_COOKIE + ","
+ Account.COL_FULL_NAME + ","
+ Account.COL_PROFILE_PIC
+ " FROM cookies");
// Drop old cookies table
db.execSQL("DROP TABLE cookies");
// Create favorite backup table
db.execSQL("CREATE TABLE " + Favorite.TABLE_NAME + "_backup ("
+ Favorite.COL_ID + " INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
+ Favorite.COL_QUERY + " TEXT,"
+ Favorite.COL_TYPE + " TEXT,"
+ Favorite.COL_DISPLAY_NAME + " TEXT,"
+ Favorite.COL_PIC_URL + " TEXT,"
+ Favorite.COL_DATE_ADDED + " INTEGER)");
// Insert all data from table 'favorite' to 'favorite_backup'
db.execSQL("INSERT INTO " + Favorite.TABLE_NAME + "_backup ("
+ Favorite.COL_QUERY + ","
+ Favorite.COL_TYPE + ","
+ Favorite.COL_DISPLAY_NAME + ","
+ Favorite.COL_PIC_URL + ","
+ Favorite.COL_DATE_ADDED + ") "
+ "SELECT "
+ Favorite.COL_QUERY + ","
+ Favorite.COL_TYPE + ","
+ Favorite.COL_DISPLAY_NAME + ","
+ Favorite.COL_PIC_URL + ","
+ Favorite.COL_DATE_ADDED
+ " FROM " + Favorite.TABLE_NAME);
// Drop favorites
db.execSQL("DROP TABLE " + Favorite.TABLE_NAME);
// Rename favorite_backup to favorites
db.execSQL("ALTER TABLE " + Favorite.TABLE_NAME + "_backup RENAME TO " + Favorite.TABLE_NAME);
} }
}; private val MIGRATION_5_6: Migration = object : Migration(5, 6) {
override fun migrate(database: SupportSQLiteDatabase) {
static final Migration MIGRATION_4_5 = new Migration(4, 5) { database.execSQL("CREATE TABLE IF NOT EXISTS `recent_searches` (" +
@Override "`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
public void migrate(@NonNull final SupportSQLiteDatabase database) { "`ig_id` TEXT NOT NULL, " +
database.execSQL("CREATE TABLE IF NOT EXISTS `dm_last_notified` (" + "`name` TEXT NOT NULL, " +
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " + "`username` TEXT, " +
"`thread_id` TEXT, " + "`pic_url` TEXT, " +
"`last_notified_msg_ts` INTEGER, " + "`type` TEXT NOT NULL, " +
"`last_notified_at` INTEGER)"); "`last_searched_on` INTEGER NOT NULL)")
database.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_dm_last_notified_thread_id` ON `dm_last_notified` (`thread_id`)"); database.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_recent_searches_ig_id_type` ON `recent_searches` (`ig_id`, `type`)")
}
} }
};
static final Migration MIGRATION_5_6 = new Migration(5, 6) { private fun backupOldFavorites(db: SupportSQLiteDatabase): List<Favorite> {
@Override // check if old favorites table had the column query_display
public void migrate(@NonNull final SupportSQLiteDatabase database) { val queryDisplayExists = checkColumnExists(db, Favorite.TABLE_NAME, "query_display")
database.execSQL("CREATE TABLE IF NOT EXISTS `recent_searches` (" + Log.d(TAG, "backupOldFavorites: queryDisplayExists: $queryDisplayExists")
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " + val oldModels: MutableList<Favorite> = ArrayList()
"`ig_id` TEXT NOT NULL, " + val sql = ("SELECT "
"`name` TEXT NOT NULL, " + + "query_text,"
"`username` TEXT, " + + "date_added"
"`pic_url` TEXT, " + + (if (queryDisplayExists) ",query_display" else "")
"`type` TEXT NOT NULL, " + + " FROM " + Favorite.TABLE_NAME)
"`last_searched_on` INTEGER NOT NULL)"); try {
database.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_recent_searches_ig_id_type` ON `recent_searches` (`ig_id`, `type`)"); db.query(sql).use { cursor ->
} if (cursor != null && cursor.moveToFirst()) {
}; do {
try {
@NonNull val queryText = cursor.getString(cursor.getColumnIndex("query_text"))
private static List<Favorite> backupOldFavorites(@NonNull final SupportSQLiteDatabase db) { val favoriteTypeQueryPair = Utils.migrateOldFavQuery(queryText) ?: continue
// check if old favorites table had the column query_display val type = favoriteTypeQueryPair.first
final boolean queryDisplayExists = checkColumnExists(db, Favorite.TABLE_NAME, "query_display"); val query = favoriteTypeQueryPair.second
Log.d(TAG, "backupOldFavorites: queryDisplayExists: " + queryDisplayExists); val epochMillis = cursor.getLong(cursor.getColumnIndex("date_added"))
final List<Favorite> oldModels = new ArrayList<>(); val localDateTime = LocalDateTime.ofInstant(
final String sql = "SELECT " Instant.ofEpochMilli(epochMillis),
+ "query_text," ZoneId.systemDefault()
+ "date_added" )
+ (queryDisplayExists ? ",query_display" : "") oldModels.add(Favorite(
+ " FROM " + Favorite.TABLE_NAME; 0,
try (final Cursor cursor = db.query(sql)) { query,
if (cursor != null && cursor.moveToFirst()) { type,
do { if (queryDisplayExists) cursor.getString(cursor.getColumnIndex("query_display")) else null,
try { null,
final String queryText = cursor.getString(cursor.getColumnIndex("query_text")); localDateTime
final Pair<FavoriteType, String> favoriteTypeQueryPair = Utils.migrateOldFavQuery(queryText); ))
if (favoriteTypeQueryPair == null) continue; } catch (e: Exception) {
final FavoriteType type = favoriteTypeQueryPair.first; Log.e(TAG, "onUpgrade", e)
final String query = favoriteTypeQueryPair.second; }
final long epochMillis = cursor.getLong(cursor.getColumnIndex("date_added")); } while (cursor.moveToNext())
final LocalDateTime localDateTime = LocalDateTime.ofInstant(
Instant.ofEpochMilli(epochMillis),
ZoneId.systemDefault()
);
oldModels.add(new Favorite(
0,
query,
type,
queryDisplayExists ? cursor.getString(cursor.getColumnIndex("query_display")) : null,
null,
localDateTime
));
} catch (Exception e) {
Log.e(TAG, "onUpgrade", e);
} }
} while (cursor.moveToNext()); }
} catch (e: Exception) {
Log.e(TAG, "onUpgrade", e)
} }
} catch (Exception e) { Log.d(TAG, "backupOldFavorites: oldModels:$oldModels")
Log.e(TAG, "onUpgrade", e); return oldModels
} }
Log.d(TAG, "backupOldFavorites: oldModels:" + oldModels);
return oldModels;
}
private static synchronized void insertOrUpdateFavorite(@NonNull final SupportSQLiteDatabase db, @NonNull final Favorite model) { @Synchronized
final ContentValues values = new ContentValues(); private fun insertOrUpdateFavorite(db: SupportSQLiteDatabase, model: Favorite) {
values.put(Favorite.COL_QUERY, model.getQuery()); val values = ContentValues()
values.put(Favorite.COL_TYPE, model.getType().toString()); values.put(Favorite.COL_QUERY, model.query)
values.put(Favorite.COL_DISPLAY_NAME, model.getDisplayName()); values.put(Favorite.COL_TYPE, model.type.toString())
values.put(Favorite.COL_PIC_URL, model.getPicUrl()); values.put(Favorite.COL_DISPLAY_NAME, model.displayName)
values.put(Favorite.COL_DATE_ADDED, model.getDateAdded().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); values.put(Favorite.COL_PIC_URL, model.picUrl)
int rows; values.put(Favorite.COL_DATE_ADDED, model.dateAdded!!.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli())
if (model.getId() >= 1) { val rows: Int = if (model.id >= 1) {
rows = db.update(Favorite.TABLE_NAME, db.update(Favorite.TABLE_NAME,
SQLiteDatabase.CONFLICT_IGNORE, SQLiteDatabase.CONFLICT_IGNORE,
values, values,
Favorite.COL_ID + "=?", Favorite.COL_ID + "=?", arrayOf(model.id.toString()))
new String[]{String.valueOf(model.getId())}); } else {
} else { db.update(Favorite.TABLE_NAME,
rows = db.update(Favorite.TABLE_NAME, SQLiteDatabase.CONFLICT_IGNORE,
SQLiteDatabase.CONFLICT_IGNORE, values,
values, Favorite.COL_QUERY + "=?" + " AND " + Favorite.COL_TYPE + "=?", arrayOf(model.query, model.type.toString()))
Favorite.COL_QUERY + "=?" + " AND " + Favorite.COL_TYPE + "=?", }
new String[]{model.getQuery(), model.getType().toString()}); if (rows != 1) {
db.insert(Favorite.TABLE_NAME, SQLiteDatabase.CONFLICT_IGNORE, values)
}
} }
if (rows != 1) {
db.insert(Favorite.TABLE_NAME, SQLiteDatabase.CONFLICT_IGNORE, values);
}
}
private static boolean checkColumnExists(@NonNull final SupportSQLiteDatabase db, @Suppress("SameParameterValue")
@NonNull final String tableName, private fun checkColumnExists(
@NonNull final String columnName) { db: SupportSQLiteDatabase,
boolean exists = false; tableName: String,
try (Cursor cursor = db.query("PRAGMA table_info(" + tableName + ")")) { columnName: String,
if (cursor.moveToFirst()) { ): Boolean {
do { var exists = false
final String currentColumn = cursor.getString(cursor.getColumnIndex("name")); try {
if (currentColumn.equals(columnName)) { db.query("PRAGMA table_info($tableName)").use { cursor ->
exists = true; if (cursor.moveToFirst()) {
do {
val currentColumn = cursor.getString(cursor.getColumnIndex("name"))
if (currentColumn == columnName) {
exists = true
}
} while (cursor.moveToNext())
} }
} while (cursor.moveToNext()); }
} catch (ex: Exception) {
Log.e(TAG, "checkColumnExists", ex)
} }
} catch (Exception ex) { return exists
Log.e(TAG, "checkColumnExists", ex);
} }
return exists;
} }
} }

View File

@ -7,8 +7,7 @@ import java.time.LocalDateTime
import java.time.ZoneId import java.time.ZoneId
import java.time.ZoneOffset import java.time.ZoneOffset
object Converters { class Converters {
@JvmStatic
@TypeConverter @TypeConverter
fun fromFavoriteTypeString(value: String?): FavoriteType? = fun fromFavoriteTypeString(value: String?): FavoriteType? =
if (value == null) null if (value == null) null
@ -18,16 +17,13 @@ object Converters {
null null
} }
@JvmStatic
@TypeConverter @TypeConverter
fun favoriteTypeToString(favoriteType: FavoriteType?): String? = favoriteType?.toString() fun favoriteTypeToString(favoriteType: FavoriteType?): String? = favoriteType?.toString()
@JvmStatic
@TypeConverter @TypeConverter
fun fromTimestampToLocalDateTime(value: Long?): LocalDateTime? = fun fromTimestampToLocalDateTime(value: Long?): LocalDateTime? =
if (value == null) null else LocalDateTime.ofInstant(Instant.ofEpochMilli(value), ZoneOffset.systemDefault()) if (value == null) null else LocalDateTime.ofInstant(Instant.ofEpochMilli(value), ZoneOffset.systemDefault())
@JvmStatic
@TypeConverter @TypeConverter
fun localDateTimeToTimestamp(localDateTime: LocalDateTime?): Long? = localDateTime?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli() fun localDateTimeToTimestamp(localDateTime: LocalDateTime?): Long? = localDateTime?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli()
} }