oligazar
6/11/2017 - 4:12 AM

Realm

Realm

// Don't forget to apply realm plugin. 
// See build.gradle(app and project)

// MyApp
private fun initRealm() {

        Realm.init(this)

        val configuration = RealmConfiguration.Builder().build()
//        val configuration = RealmConfiguration.Builder()
//                .name(Realm.DEFAULT_REALM_NAME)
//                .schemaVersion(0)
//                .deleteRealmIfMigrationNeeded()
//                .build()
        Realm.setDefaultConfiguration(configuration)
    }

// build.gradle
/* Realm */
    compile 'io.realm:android-adapters:1.3.0'
class RealmController(val realm: Realm) {

    /** Groups */

    fun addBooksToGroup(group: Group, books: ArrayList<Book>) {
        // I want to check if there some books in a specific group
        // inside realm which are not returned anymore from backend
        val oldBooks = realm.copyFromRealm(getGroupBooks(group))

        for (newBook in books) {
            // removing books existing in backend response leaves only books to delete from realm
            oldBooks.remove(newBook)

            val book = realm.where(Book::class.java).equalTo("id", newBook.id).findFirst() ?: newBook
            val time = System.currentTimeMillis()
            val groupName = realm.where(RealmString::class.java).equalTo("name", group.name).findFirst()
            realm.executeTransaction {
              // keep only data that needed locally
              // override the rest
                book.isBought = newBook.isBought
                book.dateAdd = time
                book.createdAt = newBook.createdAt
                book.icon = newBook.icon
                if (groupName == null || !book.group.contains(groupName)) book.group.add(RealmString(group.name))
                realm.copyToRealmOrUpdate(book)
            }
        }
        removeBooksFromGroup(oldBooks, group)

        if (books.isNotEmpty())logGroups(books[0])
    }

    private fun removeBooksFromGroup(books: List<Book>, group: Group) {

        for (book in books) {
            val oldBook = getBook(book.id) ?: continue
            val groupName = realm.where(RealmString::class.java).equalTo("name", group.name).findFirst() ?: continue
            realm.executeTransaction {
                oldBook.group.remove(groupName)
            }
        }
    }

    fun getGroupBooks(group: Group): RealmResults<Book> {
        var results = realm.where(Book::class.java).contains("group.name", group.name).findAll()
        if (group == Group.new) results = results.sort("createdAt", Sort.DESCENDING)
        else results = results.sort("id", Sort.ASCENDING)
        return results
    }

    /** Bookmarks */

    fun getBookmarkedBooks(): RealmResults<Book> {
        return realm.where(Book::class.java).equalTo("inBookmark", 1).findAll()
    }

    fun setBookmarked(book: Book, add: Boolean) {
        val mBook = getBook(book.id) ?: book
        realm.executeTransaction {
            mBook.inBookmark = if (add) 1 else 0
        }
    }

    fun deleteFromBookmarks(book: Book) {
        setBookmarked(book, false)
    }

    fun markBooksAsBookmarked(books: List<Book>) {
        for (book in books) {
           setBookmarked(book, true)
        }
        if (books.isNotEmpty()) logGroups(books[0])
    }

    /** History */

    fun addToHistory(book: Book) {
        val time = System.currentTimeMillis()
        val oldBook = realm.where(Book::class.java).equalTo("id", book.id).findFirst() ?: book
        realm.executeTransaction {
            // keep only data that needed locally
            // override the rest
            oldBook.dateView = time
//            if (oldBook.description.isNotEmpty()) book.description = oldBook.description
            if (oldBook.dateAdd == 0.toLong()) oldBook.dateAdd = time
            oldBook.size = book.size
            oldBook.duration = book.duration
            oldBook.icon = book.icon
            oldBook.authors = book.authors

//            oldBook.readers = book.readers
//            book.files = oldBook.files
            realm.copyToRealmOrUpdate(oldBook)
        }
    }

    fun getHistoryBooks(): RealmResults<Book> {
        return realm.where(Book::class.java).greaterThan("dateView", 0).findAll().sort("dateView", Sort.DESCENDING)
    }

    /** Book */

    fun getBook(bookId: Int): Book? {
        return realm.where(Book::class.java).equalTo("id", bookId).findFirst()
    }

    fun savePlayedBook(playedBook: PlayedBook) {
        realm.executeTransaction {
            realm.copyToRealmOrUpdate(playedBook)
        }
    }

    fun getPlayedBook(id: Int): PlayedBook? {
        val playedBook = realm.where(PlayedBook::class.java).equalTo("id", id).findFirst() ?: return null
        return realm.copyFromRealm(playedBook)
    }

    fun deletePlayedBook(id: Int) {
        realm.executeTransaction {
            realm.where(PlayedBook::class.java).equalTo("id", id).findAll().deleteAllFromRealm()
        }
    }

    /** Book Files*/

    fun saveBookFiles(book: Book, files: ArrayList<BookFile>): RealmResults<BookFile> {
        realm.executeTransaction {
            book.files.addAll(files)
            realm.copyToRealmOrUpdate(book)
        }
        val results = realm.where(BookFile::class.java).equalTo("bookId", book.id).findAllAsync()
        return results
    }

    fun getBookFiles(bookId: Int): RealmResults<BookFile> {
        // return only BookFiles where at least one item has localPath set
        val result = realm.where(BookFile::class.java).equalTo("bookId", bookId)/*.isNotEmpty("localPath")*/.findAll().sort("trackNumber", Sort.ASCENDING)
        return result
    }

    fun getBookFile(id: Int, name: String?): BookFile? {
        return realm.where(BookFile::class.java).equalTo("bookId", id).equalTo("filename", name).findFirst()
    }

    fun deleteDemoFile(id: Int) {
        realm.where(BookFile::class.java).equalTo("bookId", id).equalTo("id", 0).findAll().deleteAllFromRealm()
    }

    fun deleteBookFiles(bookId: Int) {
        realm.executeTransaction { realm ->
            val results = realm.where(BookFile::class.java).equalTo("bookId", bookId).findAll()
            results.deleteAllFromRealm()
        }
    }

    fun removeBook(id: Int) {

        realm.executeTransaction {
            realm.where(Book::class.java).equalTo("id", id).findAll().deleteAllFromRealm()
        }
    }

    fun hasBookFiles(id: Int): Boolean {
        val result = realm.where(BookFile::class.java).equalTo("bookId", id).findAll()
        return result.isNotEmpty()
    }

    /** Categories */

    //find all objects in the Book.class
    fun getCategories(): RealmResults<Category> {
        return realm.where(Category::class.java).findAllSorted("name")
    }

    fun saveCategories(categories: ArrayList<Category>) {
        // I want to check if there some categories
        // inside realm which are not returned anymore from backend
        val oldCategories = realm.copyFromRealm(getCategories())

        for (newCategory in categories) {
            oldCategories.remove(newCategory)

            realm.executeTransaction {
                realm.copyToRealmOrUpdate(newCategory)
            }
        }

        // delete all categories which are not in backend results anymore
        for (oldCategory in oldCategories) {
            realm.executeTransaction {
                realm.where(Category::class.java).equalTo("id", oldCategory.id).findAll().deleteAllFromRealm()
            }
        }
    }

    /** Collections */

    fun addCustomCollections(newCollections: List<CustomCollection>) {
        realm.executeTransaction {
            // First, remove stored in realm collections
            realm.delete(CustomCollection::class.java)
            // Then, store new CustomCollections
            realm.copyToRealmOrUpdate(newCollections)
        }
    }

    fun getCustomCollections(): RealmResults<CustomCollection> {
        return realm.where(CustomCollection::class.java).findAllSorted("ordering")
    }

    /** Other */

    fun logGroups(book: Book) {
        for (group in book.group) {
            Log.d("RealmController", "setBookmarked, group = ${group.name}")
        }
    }

    /** Bought books*/

    fun getBoughtBooks(): RealmResults<Book> {
        return realm.where(Book::class.java).equalTo("isBought", 1).findAll()
    }

    fun setBought(bookId: Int) {
        val book = getBook(bookId) ?: return
        realm.executeTransaction {
            book.isBought = 1
            realm.copyToRealmOrUpdate(book)
        }
    }

    fun markBooksAsBought(books: List<Book>) {
        for (newBook in books) {
            val book = realm.where(Book::class.java).equalTo("id", newBook.id).findFirst() ?: newBook
            realm.executeTransaction {
                book.isBought = 1
                realm.copyToRealmOrUpdate(book)
            }
        }
        if (books.isNotEmpty()) logGroups(books[0])
    }

    /** ListenBookFragment */
//
    fun saveProgress(bookId: Int, duration: Long) {
        if (duration == 0.toLong()) return
        val book = getBook(bookId) ?: return
        val progressPercent = duration * 100 / book.duration
        val progress = if (progressPercent > 0) progressPercent else 1
        realm.executeTransaction {
            book.progress = progress
            realm.copyToRealmOrUpdate(book)
        }
    }

    fun getListenedBooks(): RealmResults<Book> {
        return realm.where(Book::class.java).greaterThan("progress", 0).findAll()
    }

    fun deleteBookFromListened(bookId: Int) {
        val book = getBook(bookId) ?: return
        realm.executeTransaction {
            book.progress = 0
        }
    }

    fun saveLocalPath(id: Int, path: String, name: String?) {
        val bookFile = getBookFile(id, name) ?: return
        if (bookFile.localPath.isEmpty()) realm.executeTransaction { bookFile.localPath = path + name }
    }

    fun filterBoughtBooks(query: String): RealmResults<Book> {

        val queryCap = query.substring(0, 1).toUpperCase() + query.substring(1)
        return realm.where(Book::class.java).equalTo("isBought", 1)
                .contains("name", query, Case.INSENSITIVE)
                .or().contains("name", queryCap)
                .or().contains("authors", query)
                .or().contains("authors", queryCap)
                .findAll()
    }

    fun saveDownloadProgress(bookId: Int, downloadProgress: Long) {
        val book = realm.where(Book::class.java).equalTo("id", bookId).findFirst() ?: return
        realm.executeTransaction {
            book.downloadProgress = downloadProgress
        }
    }

    fun cleanBook(bookId: Int) {
        deleteBookFiles(bookId)
        deletePlayedBook(bookId)
        deleteBookFromListened(bookId)
    }

    fun <R: RealmModel> detach(realmObject: R): R {
        return realm.copyFromRealm(realmObject)
    }

    fun saveBookFilePath(fileId: Int, filePath: String) {
        val file = realm.where(BookFile::class.java).equalTo("id", fileId).findFirst() ?: return
        realm.executeTransaction {
            file.pathfile = filePath
            realm.copyToRealmOrUpdate(file)
        }
    }

    fun getUnmanagedBookFiles(bookId: Int): RealmResults<BookFile> {
        // return only BookFiles where at least one item has localPath set
        val result = realm.where(BookFile::class.java).equalTo("bookId", bookId).isEmpty("localPath").findAll()
        return result
    }

    fun setBookmarked(book: Book) {
        val mBook = getBook(book.id) ?: book
        realm.executeTransaction {
            mBook.inBookmark = if (mBook.inBookmark == 0) 1 else 0
            realm.copyToRealmOrUpdate(mBook)
        }
    }

    private fun isInHistory(id: Int): Boolean {
        val book = realm.where(Book::class.java).equalTo("id", id).findFirst() ?: return false
        return book.dateView != 0.toLong()
    }

    fun isInBookmarks(id: Int): Boolean {
        val book = getBook(id) ?: return false
        return book.inBookmark == 1
    }
}
// example on how to populate realm with dummy objects

  private val INTEGER_COUNTER = AtomicInteger(0)
  private fun putItemsIntoRealm() {
      (1..10).forEach { i ->
          val item = HistoryItem(INTEGER_COUNTER.getAndIncrement(), "surname $i", "name $i", "code $i", "date $i")
          realm.executeTransaction {
              realm.copyToRealmOrUpdate(item)
          }
      }
  }
    
    
    
@RealmClass
open class Book(@PrimaryKey var id: Int = 0, 
                @SerializedName("price_sale") var priceSale: Int = 0,
                var status: Int = 0, 
                var publisher: String = "", 
                var files: RealmList<BookFile> = RealmList(), 
                var group: RealmList<RealmString> = RealmList()): RealmModel {

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other?.javaClass != javaClass) return false

        other as Book
        if (id != other.id) return false
        return true
    }

    override fun hashCode(): Int {
        return id
    }
}